#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <algorithm>
#include <assert.h>

#include "yxjmj_conf.h"
#include "server.h"
#include "game_log.h"
#include "room.h"
#include "client.h"
#include "player.h"
#include "proto.h"
#include "redis_client.h"

std::map<int, int(Room::*)(Player *)> Room::_game_route =
{
{ CLIENT_ANG_GANG_REQ ,&Room::handler_player_operater_ANG_GANG },
{ CLIENT_MING_GANG_REQ ,&Room::handler_player_operater_MING_GANG },
{ CLIENT_ZIMO_HU_REQ ,&Room::handler_player_operater_ZI_MO },
{ CLIENT_OUT_MJ_REQ ,&Room::handler_player_operater_PUTOUT_MJ },
{ CLIENT_PENG_REQ ,&Room::handler_player_operater_PENG },
{ CLIENT_FANG_GANG_REQ ,&Room::handler_player_operater_FANG_GANG },
{ CLIENT_FANG_PAO_HU_REQ ,&Room::handler_player_operater_FANG_PAO_HU },
{ CLIENT_QIANG_GANG_HU_REQ ,&Room::handler_player_operater_QIANG_GANG_HU },
{ CLIENT_PASS_REQ ,&Room::handler_player_operater_PASS },
{ CLIENT_PASS2_REQ ,&Room::handler_player_operater_PASS2 },
{ CLIENT_DISSOLUTION_ROOM_REQ ,&Room::handler_player_dissolution_room_req },
{ CLIENT_DISSOLUTION_ROOM_CONFIRM ,&Room::handler_player_dissolution_room_confirm },
{ CLIENT_READY_REQ ,&Room::handler_player_ready },
{ CLIENT_NOLMAL_CHART_REQ ,&Room::handler_nolmal_chart_req },
{ CLIENT_SPEAK_REQ ,&Room::handler_speak_req },
{ CLIENT_DING_QUE_REQ ,&Room::handler_ding_que_req },
{ CLIENT_BAO_TING_REQ ,&Room::handler_bao_ting_req },
{ CLIENT_GOLDROOM_LOGOUT_ROOM ,&Room::handler_del_player },
{ CLIENT_CANCEL_ROBOT_OP_REQ ,&Room::handler_cancel_robot_op },
{ CLIENT_ROBOT_AUTO_OUT_MJ_REQ ,&Room::handler_robot_auto_out_mj }
};

Room::Room(int id) :
	isdissolution(0),
	clubid(0),
	priv_uid(0),
	password(0),
	roomid(id),
	mj_flash_stamp(4),
	dissolution_confirm_stamp(100),
	hu_mj_stamp(1),
	end_flash_stamp(12),
	din_que_stamp(20),
	_has_timer(true)
{
	mj_flash_timer.data = this;
	ev_timer_init(&mj_flash_timer, Room::mj_flash_timer_cb, mj_flash_stamp, mj_flash_stamp);	
	
	dissolution_confirm_timer.data = this;
	ev_timer_init(&dissolution_confirm_timer, Room::dissolution_confirm_timer_cb, dissolution_confirm_stamp, dissolution_confirm_stamp);
	
	hu_mj_timer.data = this;
	ev_timer_init(&hu_mj_timer, Room::hu_mj_timer_cb, hu_mj_stamp, hu_mj_stamp);
	
	end_flash_timer.data = this;
	ev_timer_init(&end_flash_timer, Room::end_flash_timer_cb, end_flash_stamp, end_flash_stamp);

	din_que_timer.data = this;
	ev_timer_init(&din_que_timer, Room::din_que_timer_cb, din_que_stamp, din_que_stamp);	
}					

Room::~Room()
{
	ev_timer_stop(YXJMJ_CONF._loop, &mj_flash_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &dissolution_confirm_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &hu_mj_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &end_flash_timer); 	
	ev_timer_stop(YXJMJ_CONF._loop, &din_que_timer); 
}

void Room::init()
{
	//如果是匹配场
	if (YXJMJ_CONF._game_flag > 1000000)
	{
		if (init_gold_room(YXJMJ_CONF._min_access
			, YXJMJ_CONF._max_access
			, YXJMJ_CONF._tai_fee
			, YXJMJ_CONF._base_gold) < 0)
		{
			GAME_LOG.error("gold room[%d] init err\n", roomid);
			exit(1);
		}
	}
}


int Room::init_private(int my_board_choose, int my_player_num )
{
    //roomid = my_roomid;
	board_choose = my_board_choose;
	player_num = my_player_num;
       
    for (int i = 0; i < 4; i++)
    {
        seats[i].seat_no = i;
        seats[i].occupied = false;
        seats[i].player = NULL;
    }
	
	next_banker_seat = 0;
	rest_board = board_choose;
	
	dice[0] = 0;
	dice[1] = 0;
	state = STATE_READY;

	rec_id = -1;
	
    return 0;
}

int Room::init_gold_room(int _min_access_gold, int _max_access_gold, int _tai_fee, int _base_gold)
{
	//roomid = _i;
	min_access_gold = _min_access_gold;
	max_access_gold = _max_access_gold;
	tai_fee = _tai_fee;
	base_gold = _base_gold;
	
	player_num = 4;
       
    for (int i = 0; i < player_num; i++)
    {
        seats[i].seat_no = i;
        seats[i].occupied = false;
        seats[i].player = NULL;
    }
	
	next_banker_seat = 0;
	rest_board = board_choose;
	
	dice[0] = 0;
	dice[1] = 0;
	state = STATE_READY;

	rec_id = -1;

	return 0;
}	


void Room::reset()
{
	gang_shang_pao_check_flag = 0;	
	cur_outmj_player = NULL;
	cur_outmj.val = 0;
	cur_qgh_player = NULL;
	cur_qgh_mj.val = 0;  
	cur_getin_player = NULL;
	cur_getin_mj = 0;
	f_player = NULL;
	end_type = 0;
	gang_mo_cnt = 0;
	banker_seat = next_banker_seat;
	fangpaiji_mj.val = 0;
	chongfengji_player = NULL;    //冲锋鸡玩家指针
	zherenji_from_player = NULL;  //打出 责任鸡玩家 
	zherenji_to_player = NULL;    //碰了凑成 责任鸡玩家	
	zherenji_type = 3;
	dice[0] = 0;
	dice[1] = 0;
}


int Room::player_enter_room(Player *player)
{	
	//不是准备状态下是不能进去的
	if ( state != STATE_READY )
	{
		GAME_LOG.error("join_room_add_player, state must[%d] STATE_READY, now state[%d].\n", STATE_READY, state);
		YXJMJ_CONF._server->send_error(player->client, 55, "游戏已经开始");
		return -1;
	}
	//房间坐不下了
	if ( (int) players.size() >= player_num)
	{
		YXJMJ_CONF._server->send_error(player->client, 55, "房间人数已满");
		return -1;
	}
	//用户已经在房间里面了
	if (players.find(player->uid) != players.end())
	{
		GAME_LOG.error("room_add_player, player aready in room. error.\n");
		return -1;
	}
	//坐下
	players[player->uid] = player;
	player->roomid = roomid;
	player->seatid = sit_down(player);
	if (player->seatid < 0)
	{
		GAME_LOG.error("room_add_player, player[%d], sit_down error.\n", player->uid);
		return -1;
	}
	//修改用户状态
	player->client->set_positon(POSITION_TABLE);
	player->status = READY;
	
	//把用户加入在线列表
	YXJMJ_CONF._server->online_players[player->uid] = player;
	
	if (YXJMJ_CONF._game_flag < 1000000)
	{
		if ( update_db_player_online(player->uid, YXJMJ_CONF._server_id, player->roomid, 1) < 0 )
		{
			GAME_LOG.fatal("player_enter_room, update db error.\n");
		}
		if ( update_gold_room_player_count(YXJMJ_CONF._server_id, YXJMJ_CONF._server->count_server_player_num()))
		{
			GAME_LOG.fatal("player_enter_room,  update_gold_room_player_count.error\n");
		}
		player->online = 1;
	}
	else
	{
		if ( update_db_player_online(player->uid, YXJMJ_CONF._server_id, player->roomid, 1) < 0 )
		{
			GAME_LOG.fatal("player_enter_room, update db error.\n");
		}
		
		if ( update_gold_room_player_count(YXJMJ_CONF._server_id, YXJMJ_CONF._server->count_server_player_num()))
		{
			GAME_LOG.fatal("player_enter_room,  update_gold_room_player_count.error\n");
		}
		player->online = 1;
	}

	player->online = 1;
	//发送进入房间报文
	Jpacket packet;
	packet.val["cmd"] = SERVER_ENTER_ROOM_UC;	
	packet.val["game_flag"] = YXJMJ_CONF._game_flag;
	packet.val["roomid"] = roomid;
	packet.val["room_pwd"] = password;
	packet.val["uid"] = player->uid;
	packet.val["board_choose"] = board_choose;
	packet.val["seatid"] = player->seatid;
	packet.val["player_num"] = player_num;
	packet.val["gold"] = player->gold;
	packet.val["clubid"] = clubid;
	packet.val["priv_uid"] = priv_uid;
	GAME_LOG.debug("SERVER_ENTER_ROOM_UC.\n");
	packet.end();
	unicast(player,packet.tostring());
	//通知现在房间里面的所有人-其它人的信息
	table_info_broadcast();
	//如果这是一个付费开房
	if (YXJMJ_CONF._game_flag < 1000000)
	{
		//如果人够了
		if ( (int)players.size() >=  player_num)
		{	
			//如果票状态不对 解散房间
			if (0 != update_room_ticket_status(rec_id, 3))
			{
				GAME_LOG.info("SERVER_ENTER_ROOM_UC.\n");
				do_dissolution_room();
				return -1;
			}
			//记录哪些用户在玩了
			std::string time_str = general_time_str();
			if (player_num == 2) {
				insert_total_end_record(roomid,board_choose,0,time_str,
				seats[0].player->uid,0,
				seats[1].player->uid,0);
			} else if (player_num == 3) {	
				insert_total_end_record(roomid,board_choose,0,time_str,
				seats[0].player->uid,0,
				seats[1].player->uid,0,
				seats[2].player->uid,0);
			} else if (player_num == 4) {
				insert_total_end_record(roomid,board_choose,0,time_str,
				seats[0].player->uid,0,
				seats[1].player->uid,0,
				seats[2].player->uid,0,
				seats[3].player->uid,0);
			}

			GAME_LOG.debug("#########ret_id = %d.\n", rec_id);
			start_game();
		}
	}
	else
	{
		int cnt = 0;
		std::map<int, Player*>::iterator it;
		for (it = players.begin(); it!=players.end(); it++)
		{
			Player *p = it->second;
			if ( p->status == 1) cnt++;	
		}
		if (cnt >= player_num)
		{
			start_game();
		}
	}
	return 0;	
}


int Room::sit_down(Player *player)
{
	for (int i = 0; i < player_num; i++)
    {
		if (!seats[i].occupied)
		{
			seats[i].occupied = true;
			seats[i].player = player;
			return i;
		}
    }
	return -1;
}

void Room::stand_up(Player *player)
{
	seats[player->seatid].occupied = false;
	seats[player->seatid].player = NULL;
}


int Room::table_info_broadcast()
{
	Jpacket packet;
	packet.val["cmd"] = SERVER_ROOM_INFO_BC;

	packet.val["game_flag"] = YXJMJ_CONF._game_flag;
	if (YXJMJ_CONF._game_flag > 1000000)
	{
		packet.val["base_gold"] = base_gold;
		packet.val["min_access_gold"] = min_access_gold;
		packet.val["max_access_gold"] = max_access_gold;
		packet.val["tai_fee"] = tai_fee;
	}
	
	packet.val["roomid"] = roomid;
	packet.val["board_choose"] = board_choose;
	packet.val["player_num"] = player_num;
	packet.val["rest_board"] = rest_board;
	std::map<int, Player*>::iterator it;
	Player *p = NULL;
	int i=0;
	for (it = players.begin(); it != players.end(); it++)
	{
		p = it->second;
		packet.val["players"][i]["uid"] = p->uid;
		packet.val["players"][i]["seatid"] = p->seatid;
		packet.val["players"][i]["nick_name"] = p->nick_name;
		packet.val["players"][i]["avater_url"] = p->avater_url;
		packet.val["players"][i]["login_ip"] = p->login_ip;
		packet.val["players"][i]["score"] = p->score;
		packet.val["players"][i]["sex"]= p->sex;
		packet.val["players"][i]["gold"] = p->gold;
		packet.val["players"][i]["diamonds"] = p->diamonds;
		packet.val["players"][i]["status"] = p->status;
		packet.val["players"][i]["online"] = p->online;		
		packet.val["players"][i]["paiwei_score"] = p->paiwei_score;
		i++;
	}
	GAME_LOG.debug("SERVER_ROOM_INFO_BC.\n");
	packet.end();	
	broadcast(NULL, packet.tostring());

	return 0;
}

int Room::start_ready()
{
	if (YXJMJ_CONF._game_flag < 1000000)
	{
		if (rest_board != 0)
		{
			Jpacket packet;
			packet.val["cmd"] = SERVER_GAME_READY_STAGE_BC;
			packet.val["roomid"] = roomid;
			GAME_LOG.debug("SERVER_GAME_READY_STAGE_BC.\n");
			packet.end();
			broadcast( NULL, packet.tostring());

			std::map<int, Player*>::iterator it;
			for ( it = players.begin(); it != players.end(); it++ )
			{
				Player *player = it->second;
				player->reset();
			}	
			state = STATE_READY;
		}
		else
		{
			do_dissolution_room();
		}
		return 0;
	}
	else
	{
	
		Jpacket packet;
		packet.val["cmd"] = SERVER_GAME_READY_STAGE_BC;
		packet.val["roomid"] = roomid;
		GAME_LOG.debug("SERVER_GAME_READY_STAGE_BC.\n");
		packet.end();
		broadcast( NULL, packet.tostring());
		
		state = STATE_READY;
		
		std::map<int, Player*> temp;
	    std::map<int, Player*>::iterator it;
	    for (it = players.begin(); it != players.end(); it++)
	    {
	        Player *p = it->second;	        
	        if (p->client == NULL)
	        {
	             temp[p->uid] = p;
	             p->logout_type = 1;
	        }
	        else if (YXJMJ_CONF._game_flag == 2000001 && p->diamonds <= min_access_gold && p->robot_flag == 0)
	        {
	        	temp[p->uid] = p;
	            p->logout_type = 2;
	        } 
	        else if (YXJMJ_CONF._game_flag != 2000001 && p->gold <= min_access_gold && p->robot_flag == 0)
	       	{
	       		temp[p->uid] = p;
	            p->logout_type = 2;
	       	}     
	    }
	    	
	    for (it = temp.begin(); it != temp.end(); it++)
		{
			Player *player = it->second;
			YXJMJ_CONF._server->del_player(player);
		}
		
		for ( it = players.begin(); it != players.end(); it++ )
		{
			Player *player = it->second;
			player->reset();
			player->start_ready_timer();
		}

		
	}

	return 0;
}



int Room::start_game()
{

	reset();
	rest_board --;	
	GAME_LOG.debug("\n#########################start_game: #### rest_board:%d.\n",rest_board);
	
	if (YXJMJ_CONF._game_flag > 1000000)
	{
		for (int i=0; i<player_num; i++)
		{	
			if (seats[i].player->robot_flag == 1)
			{
				continue;
			}
			int uid = seats[i].player->uid;

			if ( YXJMJ_CONF._game_flag == 2000001 )
			{
				decrease_diamonds(uid, -10);
				insert_diamonds_change_rec(uid, -10, "台费", "排位场扣除台费");
				seats[i].player->diamonds -= 10;
				GAME_LOG.debug("####uid:%d,  diamonds:%d \n", uid, seats[i].player->diamonds);
			}
			else
			{
				decrease_gold(uid, -tai_fee);
				insert_gold_change_rec(uid, -tai_fee, "台费", "金币场扣除台费");
				seats[i].player->gold -= tai_fee;
				GAME_LOG.debug("####uid:%d,  gold:%d \n", uid, seats[i].player->gold);
			}
		}
	}
	
	deck.fill();
	deck.shuffle(roomid);
	cur_seat = banker_seat;


	/*
	if (player_num == 2)
	{
		deck.pei_player_hole_mjs1(seats[0].player->hole_mjs);
		deck.pei_player_hole_mjs2(seats[1].player->hole_mjs);
		for (int i=0; i<27;i++)
		{
			Mj mj;
			deck.pop(mj);
		}	
	}
	else if (player_num == 3)
	{
		deck.pei_player_hole_mjs1(seats[0].player->hole_mjs);
		deck.pei_player_hole_mjs2(seats[1].player->hole_mjs);
		deck.pei_player_hole_mjs3(seats[2].player->hole_mjs);
		for (int i=0; i<39;i++)
		{
			Mj mj;
			deck.pop(mj);
		}
	}
	else if (player_num == 4)
	{		
		deck.pei_player_hole_mjs1(seats[0].player->hole_mjs);
		deck.pei_player_hole_mjs2(seats[1].player->hole_mjs);
		deck.pei_player_hole_mjs3(seats[2].player->hole_mjs);
		deck.pei_player_hole_mjs4(seats[3].player->hole_mjs);
		for (int i=0; i<42;i++)
		{
			Mj mj;
			deck.pop(mj);
		}
	}
	*/

	for (int i=0; i<player_num; i++)
	{		
		deck.get_player_hole_mjs(seats[i].player->hole_mjs);
	}

	srand(time(NULL));
	dice[0] =  (rand() + roomid)%6 + 1;
	dice[1] =  (rand() + roomid)%6 + 1;
	
	deck.get_common_mjs(comm_mjs);	
	Jpacket packet;
	packet.val["cmd"] = SERVER_GAME_START_BC;
	packet.val["banker_seatid"] = banker_seat;
	packet.val["roomid"] = roomid;
	packet.val["rest_mjs"] = comm_mjs.count();
	packet.val["rest_board"] = rest_board;
	packet.val["dice"].append(dice[0]);
	packet.val["dice"].append(dice[1]);
	for (int i=0; i<player_num; i++)
	{
		Player *p = seats[i].player;
		packet.val["players"][i]["uid"] = p->uid;
		packet.val["players"][i]["seatid"] = p->seatid;
		packet.val["players"][i]["diamonds"] = p->diamonds;
		packet.val["players"][i]["gold"] = p->gold;
		for (unsigned int j=0; j<p->hole_mjs.mjs.size(); j++)
		{
			packet.val["players"][i]["hole_mjs"].append(p->hole_mjs.mjs[j].val);
		}
		if ( p->hole_mjs.mjs.size() == 0)
		{
			packet.val["players"][i]["hole_mjs"].resize(0);
		}
	}
	GAME_LOG.debug("SERVER_GAME_START_BC.\n");
	packet.end();
	broadcast(NULL,packet.tostring());

	for (int i=0; i<player_num; i++)
	{
		seats[i].player->status = INPlAY;
	}
	
	state = STATE_MJ_FLASH;
	
	ev_timer_start(YXJMJ_CONF._loop, &mj_flash_timer);
	
	return 0;
}

int Room::start_play()
{
	if ( player_num == 2 || player_num == 3 ) //2人场，3人场 需定缺
	{
		state = STATE_DING_QUE;
		Jpacket packet;
		packet.val["cmd"] = SERVER_DINGQUE_STARGE_BC;
		packet.val["roomid"] = roomid;
		packet.end();
		GAME_LOG.info("SERVER_DINGQUE_STARGE_BC.\n");
		broadcast(NULL, packet.tostring());		
		ev_timer_start(YXJMJ_CONF._loop, &din_que_timer);
	}
	else //四人场
	{	
		start_play_2();
	}
	
	return 0;
}

int Room::start_play_2()
{
	state = STATE_PLAYING;		
	Player *cur_player = seats[cur_seat].player;
	if ( getin_mj(cur_player) == 1 )
	{
		return 0;
	}
	operate_check_after_getin_mj(cur_player);
	return 0;
}

int Room::handler_ding_que_req(Player *player)
{
	
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	int dq_val = val["dq_val"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_ding_que_req, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (dq_val != 1 && dq_val != 3 && dq_val != 5)  //万，条，筒
	{
		GAME_LOG.error("handler_ding_que_req, dq_val[%d] error.\n", dq_val);
		return -1;
	}
	if (state != STATE_DING_QUE)
	{
		GAME_LOG.error("handler_ding_que_req, uid[%d], state error, cur state\n", uid, state);
		return -1;
	}	
	if (player_num == 4)
	{
		GAME_LOG.error("four pepole game, has no ding que stage.\n");
		return -1;
	}

	player->dq_val = dq_val;

	Jpacket packet;
	packet.val["cmd"] = SERVER_DINGQUE_SUCC_BC;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["dq_val"] = dq_val;
	GAME_LOG.debug("SERVER_DINGQUE_SUCC_BC.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	int cnt=0;
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *player = it->second;
		if (player->dq_val > 0) 
			cnt++;
	}
	
	if (cnt >= player_num)
	{
		ev_timer_stop(YXJMJ_CONF._loop, &din_que_timer);

		Jpacket packet;
		packet.val["cmd"] = SERVER_ALL_DIN_QUE_SUCC_BC;
		std::map<int, Player*>::iterator it;	
		int i=0;
		for (it = players.begin(); it != players.end(); it++)
		{
			Player *p = it->second;
			packet.val["players"][i]["uid"] = p->uid;
			packet.val["players"][i]["seatid"] = p->seatid;
			packet.val["players"][i]["dq_val"] = p->dq_val;
			i++;
		}
		packet.end();
		broadcast(NULL, packet.tostring());	
		
		start_play_2();	
	}
	
	return 0;
}

int Room::robot_do_din_que()
{
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *player = it->second;
		if (player->dq_val == 0)
		{
			player->dq_val = calculate_min_que(player);
			Jpacket packet;
			packet.val["cmd"] = SERVER_DINGQUE_SUCC_BC;
			packet.val["uid"] = player->uid;
			packet.val["seatid"] = player->seatid;
			packet.val["roomid"] = player->roomid;
			packet.val["dq_val"] = player->dq_val;
			GAME_LOG.debug("SERVER_DINGQUE_SUCC_BC.\n");
			packet.end();
			broadcast(NULL, packet.tostring());
		}
	}

	Jpacket packet;
	packet.val["cmd"] = SERVER_ALL_DIN_QUE_SUCC_BC;
	int i=0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		packet.val["players"][i]["uid"] = p->uid;
		packet.val["players"][i]["seatid"] = p->seatid;
		packet.val["players"][i]["dq_val"] = p->dq_val;
		i++;
	}
	packet.end();
	broadcast(NULL, packet.tostring());	
	
	start_play_2();
	return 0;
}

int Room::calculate_min_que(Player *player)
{
	std::vector<Mj>::iterator it;
	int c1=0,c2=0,c3=0;	
	int dq = 1;
	for (it = player->hole_mjs.mjs.begin(); it != player->hole_mjs.mjs.end(); it++)
	{
		Mj mj = *it;		
		if (mj.color() == 1) c1++;
		else if (mj.color() == 2) c2++;
		else if (mj.color() == 3) c3++;		
	}
	GAME_LOG.debug("uid:%d   c1=%d, c2=%d, c3=%d\n", player->uid,c1,c2,c3);
	int min = 0;
	min = c1<c2 ? c1:c2;
	min = c3<min ? c3:min;

	GAME_LOG.debug("min=%d.\n", min);
	
	if (min == c1) dq = 1;
	else if (min == c2) dq = 3;
	else if (min == c3) dq = 5;
	GAME_LOG.debug("dq=%d.\n", dq);
	return dq;	
}



int Room::handler_player_operater_ANG_GANG(Player *player)
{
	
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, cur_seat[%d], player->seatid[%d].\n", uid, player->seatid);
		return -1;
	}
	
	int anggang_val = val["angang_mj"].asInt();
	//检查是否是合法的麻将牌
	if ( !Mj::check_mjval(anggang_val) )
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, anggang_val[%d] error.\n",anggang_val);
		return -1;
	}
	Mj mj(anggang_val);		
	//杠牌
	if ( do_ang_gang(player,mj) < 0)
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, do anggang error.\n");
		return -1;
	}
	
	player->stop_getin_outmj_timer();
	//告诉所有人这个人暗杠了
	Jpacket packet;
	packet.val["cmd"] = SERVER_ANGGANG;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["mj"] = anggang_val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_PENG.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	gang_shang_pao_check_flag = ANG_GANG;

	//用户从最后面获得一张麻将牌
	if ( getin_mj(player,1) == 1 )
	{
		return 0;
	}
	operate_check_after_getin_mj(player);

	return 0;	
}

int Room::handler_player_operater_MING_GANG(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	//明杠必须是自己刚抓的
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, cur_seat[%d], player->seatid[%d].\n", uid, player->seatid);
		return -1;
	}
	int ming_gang_val = val["ming_gang_mj"].asInt();
	if (!Mj::check_mjval(ming_gang_val))
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, ming_gang_val[%d] error.\n",ming_gang_val);
		return -1;
	}
	//如果这个牌不是刚摸得
	if (player->mo_mj.val != ming_gang_val)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, player->mo_mj.val[%d] != ming_gang_val[%d].\n", player->mo_mj.val, ming_gang_val);
		return -1;
	}
	
	//停止打牌计时器
	player->stop_getin_outmj_timer();	
	
	//清空用户的抢杠胡检测
	std::map<int, Player*>::iterator it;
	int c = 0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( p == player)
		{
			continue;
		}
		P_CHECK_QGH p_check_qgh;
		p_check_qgh.clear();
		p_check_qgh.player = p;
		m_check_qgh[c] = p_check_qgh;
		c++;
	}
	
	if ( operate_check_qiang_gang_hu( player->mo_mj, player) == 1 ) //鏈夊彲浠ユ姠鏉犺儭,鏄庢潬澶辫触
	{
		GAME_LOG.info("handler_player_operater_MING_GANG, but now other can qiang gang hu.\n");
		cur_qgh_mj = player->mo_mj;
		cur_qgh_player = player;
		return 0;
	} 
	else 
	{
		do_MING_GANG(player);
	}
	
	return 0;
}

int Room::do_MING_GANG(Player *player)
{
	if (do_ming_gang(player, player->mo_mj) < 0)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, mo_mj[%d].\n", player->mo_mj.val);
		return -1;
	}
	//是不是责任鸡
	if (player->mo_mj.val == S1)
	{
		zherenji_type = 4;
	}
	//通知所有人
	Jpacket packet;
	packet.val["cmd"] = SERVER_MINGGANG;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["mj"] = player->mo_mj.val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_MINGGANG.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	gang_shang_pao_check_flag = MING_GANG;

	//摸牌
	if ( getin_mj(player,1) == 1 )
	{
		return 0;
	}
	//摸牌后检测
	operate_check_after_getin_mj(player);

	return 0;
}

int Room::handler_bao_ting_req(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	int ting_out_mj = val["ting_out_mj"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_bao_ting_req, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_bao_ting_req, cur_seat[%d], player->seatid[%d].\n", uid, player->seatid);
		return -1;
	}
	if ( !Mj::check_mjval(ting_out_mj) )
	{
		GAME_LOG.error("handler_bao_ting_req, outmj_val[%d] error.\n", ting_out_mj);
		return -1;
	}

	//广播消息
	Jpacket packet;
	packet.val["cmd"] = SERVER_BAO_TING_SUCC_BC;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;

	form_player_all_mj_info_json(player, packet, "mjs_info");
	
	GAME_LOG.debug("SERVER_BAO_TING_SUCC_BC.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	if (do_PUTOUT_MJ(player, ting_out_mj) < 0)
	{
		GAME_LOG.error("handler_bao_ting_req, do_PUTOUT_MJ error.\n");
		return -1;
	}

	player->cur_baoting_flag = 1;

	//必须首次摸牌
	//1，如果庄家首次摸牌，天听
	if( player->seatid == banker_seat && player->mo_cnt == 1 )
	{
		player->cur_baoting_flag = 1;
	}
	//2, 非庄家，首次摸牌, 地听
	else if ( player->seatid != banker_seat && player->mo_cnt == 1 ) 
	{
		player->cur_baoting_flag = 2;
	}
	else
	{
		GAME_LOG.fatal("handler_bao_ting_req, logic fatal error.\n this fatal must not apper-------- - -! -- ");
		return -1;
	}		
	return 0; 
}


//自摸胡牌
int Room::do_zi_mo_hu(Player *player)
{
	//是否能胡牌
	if ( !check_zi_mo_hu(player) )
	{
		GAME_LOG.error("can not zi mo hu, player[%d].\n", player->uid);
		return -1;
	}	
	//停止出牌计时器
	player->stop_getin_outmj_timer();
	
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		//检测是否叫牌
		check_jiaopai_flag(p);
		if (p == player)
		{
			p->cur_pao_flag = 3; //当前玩家自摸
			p->cur_end_flag = 2; //当前玩家赢
			continue;
		}
		p->cur_end_flag = 1; //当前玩家输
	}
	//检测天胡
	if ( comm_mjs.count() == ( 108 - 13*player_num) -1) //摸的第一张牌，是庄家
	{
		player->tian_hu_flag = 1;
	}
	
	if (gang_shang_pao_check_flag == 0)
	{
		end_type = ET_ZI_MO;
	}
	else
	{
		end_type = ET_GANG_KAI_ZI_MO;
	}
	//自摸次数？有何用
	player->zimo_times ++;	
	//这局胡牌的人做庄
	next_banker_seat = player->seatid;
	return 0;
}

//放炮胡牌
int Room::do_fang_pao_hu(Player *player, Mj mj, Player *out_mj_player)
{
	if ( !check_fang_pao_hu(player ,mj, out_mj_player))
	{
		GAME_LOG.error("can not fang pao hu mj[%d], player[%d].\n", mj.val, player->uid);
		return -1;
	}
	player->hole_mjs.add_mj(mj);

	//是否地胡
	if (comm_mjs.count() == 108-player_num*13 -1)
	{
		player->di_hu_flag = 1;
	}
	
	player->card_type = calculate_card_type(player);	

	std::map<int, Player*>::iterator it;
	for (it= players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}

	player->cur_pao_flag = 2;                    //当前玩家是接炮胡，
	player->jiepao_times++;
	
	out_mj_player->cur_pao_flag = 1;     //玩家是放炮玩家

	out_mj_player->dianpao_times++;
	player->cur_end_flag = 2;           //当前玩家赢了
	out_mj_player->cur_end_flag = 1;    //当前玩家输了

	if (gang_shang_pao_check_flag == 0)
	{		
		end_type = ET_FANG_PAO;
	}
	else
	{
		end_type = ET_FANG_RE_PAO;
	}
	next_banker_seat = player->seatid;	
	return 0;
}


int Room::do_qiang_gang_hu(Player *player, Mj mj, Player *qiang_gang_player)
{
	if ( !check_qiang_gang_hu(player, mj,qiang_gang_player) )
	{
		GAME_LOG.error("can not do qiang gang hu mj[%d], qiang_gang_player[%d], player[%d].\n", mj.val, qiang_gang_player->uid, player->uid);
		return -1;
	}
	player->hole_mjs.add_mj(mj);
	player->card_type = calculate_card_type(player);

	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}

	player->cur_pao_flag = 2; //当前玩家是接炮
	qiang_gang_player->cur_pao_flag = 1;

	player->cur_end_flag = 2; //当前玩家赢了
	qiang_gang_player->cur_end_flag = 1;

	YXJMJ_CONF._server->_rooms[roomid]->end_type = ET_QIANG_GANG;
	YXJMJ_CONF._server->_rooms[roomid]->next_banker_seat = player->seatid;
	
	return 0;	
}


//计算赢番型
int Room::calculate_card_type(Player *player)
{
	int card_type = CARD_TYPE_PINGHU;
	//是否清一色
	if ( ! logic_check_qing_yi_se( player->hole_mjs, player->form_mjs, player->out_mjs) ) //不是
	{
		int qidui_val = logic_check_qidui(player->hole_mjs, player->form_mjs, player->out_mjs);
		if ( qidui_val == 1 ) //七对
		{
			card_type = CARD_TYPE_QIDUI;
		}
		else if (qidui_val == 2) //龙七对 有一组4个一样的
		{
			card_type = CARD_TYPE_LONGQIDUI;
		}
		else if ( logic_check_dandiao(player->hole_mjs,player->form_mjs,player->out_mjs) ) //单吊 手上就一张牌在等胡
		{
			card_type = CARD_TYPE_DANDIAO;
		}
		else if (logic_check_pengpenghu(player->hole_mjs,player->form_mjs,player->out_mjs) ) //碰碰胡(大对子)
		{
			card_type = CARD_TYPE_DADUIZI;
		}
	}
	else 
	{
		card_type = CARD_TYPE_QINGYISE;
	
		int qidui_val = logic_check_qidui(player->hole_mjs,player->form_mjs,player->out_mjs);
		if ( qidui_val == 1 ) //清一色七对
		{
			card_type = CARD_TYPE_QINGQIDUI;
		}
		else if ( qidui_val == 2 ) //清一色龙七对(清龙背)
		{
			card_type = CARD_TYPE_QINGLONGBEI;
		}
		else if (logic_check_dandiao(player->hole_mjs,player->form_mjs,player->out_mjs)) //清一色单吊
		{
			card_type = CARD_TYPE_DANDIAOQINGYISE; 
		}
		else if (logic_check_pengpenghu(player->hole_mjs,player->form_mjs,player->out_mjs) ) //清一色碰碰胡(清大对)
		{
			card_type = CARD_TYPE_QINGDADUI;
		}
	}

	if (player->tian_hu_flag == 1)
	{
		if ( card_type < CARD_TYPE_TIANHU )
		{
			card_type = CARD_TYPE_TIANHU;
		}
	}
	else if (player->di_hu_flag == 1)
	{
		if ( card_type < CARD_TYPE_DIHU)
		{
			card_type = CARD_TYPE_DIHU;
		}
	}

	if (player->cur_baoting_flag == 1 && player->seatid == banker_seat)
	{
		if ( card_type < CARD_TYPE_TIAN_TING)
		{
			card_type = CARD_TYPE_TIAN_TING;
		}
	}
	else if (player->cur_baoting_flag == 2 && player->seatid != banker_seat)
	{
		if ( card_type < CARD_TYPE_DI_TING)
		{
			card_type = CARD_TYPE_DI_TING;
		}
	}
	return card_type;
}

//叫嘴玩家最大胡牌牌型
int Room::check_ting_max_cardtype(Player *player)
{
	if (player->jiaopai_flag == 0) 
		return 0;

	int max_card_type = 0;

	int count = player->hole_mjs.mjs.size();
	if (count%3 != 1)
	{
		GAME_LOG.error("check_ting_max_cardtype, v_mjs size error.\n");
		return max_card_type;
	}
	
	for (int mj_val=S1; mj_val<=S9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->hole_mjs.mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->hole_mjs.mjs.push_back(mj);
		if ( check_hupai(mjs_temp, player->dq_val) )
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type) 
			{
				max_card_type = card_type;
			}
		}
		player->hole_mjs.mjs.pop_back();
	}
	
	for (int mj_val=T1; mj_val<=T9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->hole_mjs.mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->hole_mjs.mjs.push_back(mj);
		if ( check_hupai(mjs_temp, player->dq_val) )
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type) 
			{
				max_card_type = card_type;
			}

		}
		player->hole_mjs.mjs.pop_back();


	}
	
	for (int mj_val=W1; mj_val<=W9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->hole_mjs.mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->hole_mjs.mjs.push_back(mj);
		if ( check_hupai(mjs_temp, player->dq_val) )
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type) 
			{
				max_card_type = card_type;
			}
		}
		player->hole_mjs.mjs.pop_back();

	}	
	
	return max_card_type;
}


//叫嘴玩家胡牌牌型(听牌)
int Room::calculate_jiaopai_card_type(Player *player)
{
	if (player->jiaopai_flag == 0) 
		return 0;
	
	if ( player->hole_mjs.mjs.size()%3 == 2)
	{
		return calculate_card_type(player);
	}
	
	if ( player->hole_mjs.mjs.size()%3 == 1 )
	{
		return check_ting_max_cardtype(player);
	}

	return 0;
}



int Room::handler_player_operater_ZI_MO(Player *player)
{

	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, uid[%d],cur_seat[%d], player->seatid[%d].\n", uid, cur_seat, player->seatid);
		return -1;
	}	
	if (do_zi_mo_hu(player) < 0)
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, but zi mo hu error.\n");
		return  -1;
	}
	//计算胡牌牌型
	player->card_type = calculate_card_type(player);
	
	calculate_cardtype_score(player->card_type, player, NULL, NULL); 

	calculate_total_winlose_score();
	
	//鑳＄墝鎴愬姛
	Jpacket packet;
	packet.val["cmd"] = SERVER_ZIMOHU;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_ZIMOHU.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	//娓告垙缁撶畻
	ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);

	return 0;
}




int Room::handler_player_operater_PUTOUT_MJ(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player->seatid[%d].\n", uid, player->seatid);
		return -1;
	}
	if (player->hole_mjs.mjs.size() %3 != 2 )
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player hole mjs not 3n+2.\n", uid);
		return -1;
	}
	int outmj_val = val["out_mj"].asInt();

	do_PUTOUT_MJ(player, outmj_val);
	
	return 0;
}

int Room::handler_robot_auto_out_mj(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if ( uid != player->uid )
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, uid[%d],player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player->seatid[%d].\n", uid, player->seatid);
		return -1;
	}
	if (player->hole_mjs.mjs.size() %3 != 2 )
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player hole mjs not 3n+2.\n", uid);
		return -1;
	}

	int num = player->hole_mjs.mjs.size();
	int outmj_val = player->hole_mjs.mjs[num-1].val;
	do_PUTOUT_MJ(player, outmj_val);
	
	return 0;
	
}



int Room::do_PUTOUT_MJ(Player *player, int outmj_val)
{
	
	
	if (!Mj::check_mjval(outmj_val))
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, outmj_val[%d] error.\n",outmj_val);
		return -1;
	}
	
	Mj outmj(outmj_val);
	
	{
		//检查麻将是否在hole_mjs中
		std::vector<Mj>::iterator it;
		for (it = player->hole_mjs.mjs.begin(); it != player->hole_mjs.mjs.end(); it++)
		{
			Mj mj = *it;
			if (mj.val == outmj.val)
			{
				break;
			}
		}
		if (it == player->hole_mjs.mjs.end()) {
			GAME_LOG.error("do_PUTOUT_MJ, outmj[%d], not in hole_mjs.\n", outmj.val);
			return -1;
		}
	}

	player->stop_getin_outmj_timer();
	do_out_mj(player,outmj);
	
	cur_outmj_player = player;
	cur_outmj = outmj;

	//清楚这些用户的回应状态
	std::map<int, Player*>::iterator it;
	int c = 0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( p == player)
		{
			continue;
		}
		P_CHECK pcheck;
		pcheck.clear();
		pcheck.player = p;
		m_check[c] = pcheck;
		c++;
	}
	
	//广播打出去的这个牌
	Jpacket packet;
	packet.val["cmd"] = SERVER_OUT_ONE_MJ;
	packet.val["uid"] = player->uid;
	packet.val["roomid"] = roomid;
	packet.val["seatid"] = player->seatid;
	packet.val["out_mj"] = outmj.val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_OUT_ONE_MJ.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	
	//手牌排序
	player->hole_mjs.sort();
	
	//改状态
	player->status = INPLAY_AFTER_PUTOUT_MJ;
	operate_check_after_putout_mj(outmj, player);
	return 0;
}

int Room::handler_player_operater_PENG(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_PENG, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}	
	int m_i = -1;
	for (int i=0; i < player_num-1; i++)
	{
		if (m_check[i].player == player)
		{
			m_i = i;
			break;	
		}			
	}
	if (m_i == -1) 
	{
		GAME_LOG.fatal("handler_player_operater_PENG, submit uid not in m_check arr.\n");
		return -1;
	}
	if ( m_check[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_PENG, player_operation not OP_NOT_CHECK\n");
		return -1;
	}

	if (do_peng(player,cur_outmj_player,cur_outmj) < 0)
	{
		GAME_LOG.error("cur player[%d] can not peng outmj[%d].\n", player->uid, cur_outmj.val);
		return -1;	
	}
	
	m_check[m_i].player_operation = OP_PENG;
	player->stop_pass_timer();

	cur_seat = player->seatid;
	//发送碰牌成功
	Jpacket packet;
	packet.val["cmd"] = SERVER_PENG;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["mj"] = cur_outmj.val;
	packet.val["from_seatid"] = cur_outmj_player->seatid;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_PENG.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	gang_shang_pao_check_flag = 0;


	//责任鸡广播
	if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
	{
		zherenji_from_player = cur_outmj_player;
		zherenji_to_player = player;
		zherenji_type = 3;
		Jpacket packet;
		packet.val["cmd"] = SERVER_ZHE_REN_JI_BC;
		packet.val["zherenji_from_uid"] = zherenji_from_player->uid;
		packet.val["zherenji_from_seatid"] = zherenji_from_player->seatid;
		//packet.val["zherenji_to_uid"] = zherenji_to_player->uid;
		//packet.val["zherenji_to_seatid"] = zherenji_to_player->seatid;
		packet.val["uid"] = zherenji_to_player->uid;
		packet.val["seatid"] = zherenji_to_player->seatid;
		
		GAME_LOG.debug("SERVER_ZHE_REN_JI_BC.\n");
		packet.end();
		broadcast(NULL, packet.tostring());
	}

	player->status = INPLAY_AFTER_PENG_MJ;
	std::map<int, Player*>::iterator it;
	for(it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( p == player) continue;
		p->status = INPlAY;
	}
	
	//碰牌后看能否杠牌，听牌
	operate_check_after_peng_mj(player);

	return 0;
}

int Room::handler_player_operater_FANG_GANG(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	
	player->stop_pass_timer();
	
	int m_i = -1;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == player)
		{
			m_i = i;
			break;	
		}			
	}
	if (m_i == -1) 
	{
		GAME_LOG.fatal("handler_player_operater_FANG_GANG, submit uid not in m_check arr.\n");
		return -1;
	}
	if ( m_check[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, player_operation not OP_NOT_CHECK.\n");
		return -1;
	}
	m_check[m_i].player_operation = OP_GANG;

	if ( do_fang_gang(player, cur_outmj_player, cur_outmj) < 0)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, player[%d], out_mj[%d], do_fang_gang error.\n", player->uid, cur_outmj.val);
		return -1;
	}
	
	cur_seat = player->seatid;		
	
	//发送放杠成功
	Jpacket packet;
	packet.val["cmd"] = SERVER_FANG_GANG;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["mj"] = cur_outmj.val;	
	packet.val["from_seatid"] = cur_outmj_player->seatid;
	form_player_all_mj_info_json(player, packet,"mjs_info");
	GAME_LOG.debug("SERVER_FANG_GANG.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	
	gang_shang_pao_check_flag = FANG_GANG;

	//责任鸡检查
	if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
	{
		zherenji_from_player = cur_outmj_player;
		zherenji_to_player = player;
		zherenji_type = 4;
		Jpacket packet;
		packet.val["cmd"] = SERVER_ZHE_REN_JI_BC;
		packet.val["zherenji_from_uid"] = zherenji_from_player->uid;
		packet.val["zherenji_from_seatid"] = zherenji_from_player->seatid;
		//packet.val["zherenji_to_uid"] = zherenji_to_player->uid;
		//packet.val["zherenji_to_seatid"] = zherenji_to_player->seatid;
		packet.val["uid"] = zherenji_to_player->uid;
		packet.val["seatid"] = zherenji_to_player->seatid;
		GAME_LOG.debug("SERVER_ZHE_REN_JI_BC.\n");
		packet.end();
		broadcast(NULL, packet.tostring());
	}

	
	//再摸一张牌	
	if ( getin_mj(player,1) == 1 )
	{
		return 0;
	}
	
	operate_check_after_getin_mj(player);
	
	return 0;
}

int Room::handler_player_operater_FANG_PAO_HU(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	
	player->stop_pass_timer();
	
	int m_i = -1;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == player)
		{
			m_i = i;
			break;	
		}			
	}
	if (m_i == -1) 
	{
		GAME_LOG.fatal("handler_player_operater_FANG_PAO_HU, submit uid not in m_check arr.\n");
		return -1;
	}
	if ( m_check[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, player_operation not OP_NOT_CHECK\n");
		return -1;
	}

	m_check[m_i].player_operation = OP_HU;
	
	if (do_fang_pao_hu(player, cur_outmj,cur_outmj_player) < 0)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, player[%d], out_mj[%d], do_fang_pao_hu error.\n", player->uid, cur_outmj.val);
		return -1;
	}

	//冲锋鸡
	if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
	{
		chongfengji_player = cur_outmj_player;
		Jpacket packet;
		packet.val["cmd"] = SERVER_CHONG_FENG_JI_BC;
		//packet.val["chongfengji_uid"] = chongfengji_player->uid;
		//packet.val["chongfengji_seat"] = chongfengji_player->seatid;
		packet.val["uid"] = chongfengji_player->uid;
		packet.val["seatid"] = chongfengji_player->seatid;
		GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
		packet.end();
		broadcast(NULL, packet.tostring());
	}

	//发送放炮胡成功
	Jpacket packet;
	packet.val["cmd"] = SERVER_FANG_PAO_HU;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["mj"] = cur_outmj.val;	
	packet.val["from_seatid"] = cur_outmj_player->seatid;
	form_player_all_mj_info_json(player, packet,"mjs_info");
	GAME_LOG.debug("SERVER_FANG_PAO_HU.\n");
	packet.end();
	broadcast(NULL, packet.tostring());


	//牌型	
	player->card_type = calculate_card_type(player);
	calculate_cardtype_score(player->card_type, NULL, cur_outmj_player, player); 
	
	if (! if_ypsx())
	{
		calculate_total_winlose_score();
		cur_seat = player->seatid;
		ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);
	}
	else //一炮多响
	{
		if (outmj_ypsx_player_all_check())
		{
			GAME_LOG.debug("ypsx, fangpao_hu, a.\n");
			calculate_total_winlose_score();			
			cur_seat = player->seatid;
			ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);
		}
		else
		{			
			GAME_LOG.debug("ypsx, fangpao_hu, b.\n");
			//noting to do 
		}
	}
	
	return 0;
}

int Room::handler_player_operater_QIANG_GANG_HU(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}

	int m_i = -1;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check_qgh[i].player == player)
		{
			m_i = i;
			break;
		}
	}
	if (m_i == -1) 
	{
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU, player[%d] not in m_check_qgh arr.\n", uid);
		return -1;
	}
	if ( m_check_qgh[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_QIANG_GANG_HU, player[%d] player_operation not OP_NOT_CHECK\n", uid);
		return -1;
	}

	int opt = val["opt"].asInt();
	if ( opt == 0) //琛ㄧず涓嶆姠鏉犺儭
	{
		GAME_LOG.debug("m_i:%d.\n", m_i);
		m_check_qgh[m_i].player_operation = OP_PASS;
		int cnt = 0;
		for (int i=0; i<player_num-1; i++)
		{			
			GAME_LOG.debug("m_check_qgh[%d].player_operation=%d.\n", i, m_check_qgh[i].player_operation);
			if (m_check_qgh[i].player_operation == OP_PASS)
			{
				cnt++;
				if (cnt >= player_num-1)
				{					
					//都不抢杠, 继续明杠
					 do_MING_GANG(cur_qgh_player);
					return 0;
				}
			}
			else if (m_check_qgh[i].player_operation == OP_NOT_CHECK) //还有未抢杠胡的继续发送抢杠胡。
			{
				send_bar_operate_check_qiang_gang_hu(m_check_qgh[i].player, cur_qgh_mj);
				return 0;
			}
		}	

	}
	else if ( opt == 1 ) //琛ㄧず鎶㈡潬鑳?
	{
		if ( do_qiang_gang_hu(player, cur_qgh_mj, cur_qgh_player) < 0)
		{
			GAME_LOG.error("do_qiang_gang_hu error.\n");
			return -1;
		}

		player->card_type = calculate_card_type(player);
		calculate_cardtype_score(player->card_type, NULL, cur_qgh_player, player); 
		calculate_total_winlose_score();
		
		m_check_qgh[m_i].player_operation = OP_HU;
		
		//发送抢杠胡
		Jpacket packet;
		packet.val["cmd"] = SERVER_QIANG_GANG_HU;
		packet.val["uid"] = player->uid;
		packet.val["seatid"] = player->seatid;
		packet.val["roomid"] = player->roomid;
		packet.val["mj"] = cur_qgh_mj.val;
		form_player_all_mj_info_json(player, packet,"mjs_info");
		GAME_LOG.debug("SERVER_QIANG_GANG_HU.\n");
		packet.end();
		broadcast(NULL, packet.tostring());		

		ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);
	}
	
	return 0;
}

int Room::do_qiangganghu_timeout_pass(Player *player)
{
	int m_i = -1;
	int m_o = -1;
	for (int i=0; i<2; i++)
	{
		if (m_check_qgh[i].player == player)
		{
			m_i = i;
		}
		else
		{
			m_o = i;
		}
	}
	if (m_i == -1) 
	{
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU,m_i -1.\n");
		return -1;
	}
	else if (m_o == -1)
	{		
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU, mo -1\n");
		return -1;
	}
	if ( m_check_qgh[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_QIANG_GANG_HU, player[%d] player_operation not OP_NOT_CHECK\n", m_check_qgh[m_i].player->uid);
		return -1;
	}

	GAME_LOG.debug("m_i:%d.\n", m_i);
	m_check_qgh[m_i].player_operation = OP_PASS; //timeout 涓嶆姠鏉?
	GAME_LOG.debug("m_check_qgh[0].player_operation=%d, m_check_qgh[1].player_operation=%d.\n", m_check_qgh[0].player_operation, m_check_qgh[1].player_operation);


	if ( m_check_qgh[0].player_operation != OP_NOT_CHECK 
		&& m_check_qgh[1].player_operation != OP_NOT_CHECK ) //涓や釜鐜╁閮芥搷浣滃畬姣曪紝涓旀湁鐜╁鐐逛簡鎶㈡潬鑳?,娓告垙
	{
		if ( m_check_qgh[0].player_operation == OP_PASS
			&& m_check_qgh[1].player_operation == OP_PASS )
		{
			//閮戒笉鎶㈡潬, 缁х画鏄庢潬
			do_MING_GANG(cur_qgh_player);
		}
		else
		{
			if ( do_qiang_gang_hu(m_check_qgh[m_o].player, cur_qgh_mj, cur_qgh_player) < 0)
			{
				GAME_LOG.error("do_qiang_gang_hu error22.\n");
				return -1;
			}
			//鍙戦€佹姠鏉犺儭
			Jpacket packet;
			packet.val["cmd"] = SERVER_QIANG_GANG_HU;
			packet.val["uid"] = m_check_qgh[m_o].player->uid;
			packet.val["seatid"] = m_check_qgh[m_o].player->seatid;
			packet.val["roomid"] = m_check_qgh[m_o].player->roomid;
			form_player_all_mj_info_json(m_check_qgh[m_o].player, packet,"mjs_info");
			GAME_LOG.debug("SERVER_QIANG_GANG_HU22.\n");
			packet.end();
			broadcast(NULL, packet.tostring());

			next_banker_seat = cur_qgh_player->seatid;
			ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);
		}
	}
	
	return 0;
}



int Room::handler_player_operater_PASS(Player *player)
{
	if ( state != STATE_PLAYING )
	{
		GAME_LOG.error("handler_player_operater_PASS, game_state not STATE_PLAYER.\n");
		return -1;	
	}
	
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_PASS, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	
	player->stop_pass_timer();
	
	do_pass(player);
	return 0;
}

int Room::handler_player_operater_PASS2(Player *player)
{
	if ( state != STATE_PLAYING )
	{
		GAME_LOG.error("handler_player_operater_PASS2, game_state not STATE_PLAYER.\n");
		return -1;	
	}
	
	Json::Value &val = player->client->packet.tojson();
	int uid = val["uid"].asInt();
	if (uid != player->uid)
	{
		GAME_LOG.error("handler_player_operater_PASS2, uid[%d], player->uid[%d].\n", uid, player->uid);
		return -1;
	}
	if (player->seatid != cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PASS2, uid[%d],cur_seat[%d], player->seatid[%d].\n", uid, cur_seat, player->seatid);
		return -1;
	}	
	
	if ( player->status !=  INPLAY_AFTER_GETIN_MJ )
	{
		GAME_LOG.error("handler_player_operater_PASS2, player[%d] status[%d] not INPLAY_AFTER_GETIN_MJ[3].\n", player->uid, player->status);
		return -1;
	}
	
	if ( ! check_zi_mo_hu(player)  && !check_ang_gang(player,player->mo_mj) && !check_ming_gang(player, player->mo_mj)) //鍙鐞嗚嚜鎽歌繃鐗岀殑鎯呭喌锛屾殫鏉犺繃鐗岀殑 鎯呭喌
	{
		return 0;
	}

	//姝ゆ椂鑷姩鍑虹墝
	if ( player->cur_baoting_flag )
	{
		do_PUTOUT_MJ(player,player->mo_mj.val);
	}	
	return 0;
}

int Room::do_pass(Player *player)
{
	int m_i = -1;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == player)
		{
			m_i = i;
			break;	
		}			
	}
	
	if (m_i == -1) 
	{
		GAME_LOG.fatal("do_pass, player[%d] not in m_check arr.\n",player->uid);
		return -1;
	}
	if ( m_check[m_i].player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("do_pass, player[%d] player_operation not OP_NOT_CHECK.\n", player->uid);
		return -1;
	}

	if ( m_check[m_i].fangpao_hu_flag == true) //能胡不胡，本圈过手不能胡
	{
		player->guo_shou_bu_hu_flag = 1;
	}
	
	m_check[m_i].player_operation = OP_PASS;

	Jpacket packet;
	packet.val["cmd"] = SERVER_PASS;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	GAME_LOG.debug("SERVER_PASS.\n");
	packet.end();
	unicast(player, packet.tostring());

	if ( !if_ypsx() )
	{
		if (outmj_all_check())
		{
			cur_seat = next_seat(cur_seat);
			Player *player = seats[cur_seat].player;
			gang_shang_pao_check_flag = 0;

			//冲锋鸡
			if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
			{
				chongfengji_player = cur_outmj_player;
				Jpacket packet;
				packet.val["cmd"] = SERVER_CHONG_FENG_JI_BC;
				//packet.val["chongfengji_uid"] = chongfengji_player->uid;
				//packet.val["chongfengji_seat"] = chongfengji_player->seatid;
				packet.val["uid"] = chongfengji_player->uid;
				packet.val["seatid"] = chongfengji_player->seatid;
				GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
				packet.end();
				broadcast(NULL, packet.tostring());
			}

			if ( getin_mj(player) == 1 )
			{
				return 0;
			}
			operate_check_after_getin_mj(player);	
		}
		else
		{
			for (int i=0; i<player_num-1; i++)
			{
				if (m_check[i].player_operation == OP_NOT_CHECK)
				{
					send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);
					m_check[i].player->start_pass_timer();
					return 0;
				}
			}
		}
	}
	else //一炮多响
	{
		if ( outmj_all_pass() )
		{
			GAME_LOG.debug("ypsx, pass, a.\n");
			cur_seat = next_seat(cur_seat);
			Player *player = seats[cur_seat].player;
			gang_shang_pao_check_flag = 0;
			
			//冲锋鸡
			if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
			{
				chongfengji_player = cur_outmj_player;
				Jpacket packet;
				packet.val["cmd"] = SERVER_CHONG_FENG_JI_BC;
				//packet.val["chongfengji_uid"] = chongfengji_player->uid;
				//packet.val["chongfengji_seat"] = chongfengji_player->seatid;
				packet.val["uid"] = chongfengji_player->uid;
				packet.val["seatid"] = chongfengji_player->seatid;

				GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
				packet.end();
				broadcast(NULL, packet.tostring());
			}

			
			if ( getin_mj(player) == 1 )
			{
				return 0;
			}
			operate_check_after_getin_mj(player);	
		}
		else if ( outmj_hu_player_all_pass() )
		{			
			GAME_LOG.debug("ypsx, pass, b.\n");
			for (int i=0; i<player_num-1; i++)
			{
				if (m_check[i].player_operation == OP_NOT_CHECK && m_check[i].fangpao_hu_flag == false && m_check[i].peng_flag == true) //两个人能胡，都pass, 另外一个能碰	
				{
					send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);
					m_check[i].player->start_pass_timer();
					return 0;
				}
			}
		}
		else if ( outmj_ypsx_player_all_check() && outmj_ypsx_player_check_has_hu() )
		{
			GAME_LOG.debug("ypsx, pass, c.\n");
			GAME_LOG.debug("ypsx, one player pass, has player do hu. all do.\n");
			calculate_total_winlose_score();			
			ev_timer_start(YXJMJ_CONF._loop, &hu_mj_timer);
		}
		else
		{			
			GAME_LOG.debug("ypsx, pass, d.\n");
			//do noting
		}
	}	
	return 0;
}

int Room::handler_player_dissolution_room_req(Player *player)
{
	if (YXJMJ_CONF._game_flag > 1000000)
	{
		GAME_LOG.debug("only kaifang room can diss room.\n");
		return 0;
	}
	//娓呯悊鍒濆鍊?
	std::map<int,Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( p == player ) 
		{	
			p->agree_dissroom = 1;//鍙戣捣鑰?
		}
		else
		{
			p->agree_dissroom = 0; //鏈洖澶?
		}
	}
	
	if ( (int)(players.size()) < player_num 
		&& state == STATE_READY 
		&& rest_board == board_choose)
	{
		isdissolution = player->client->packet["dissolution"].asInt();
		do_dissolution_room();
	}
	else 
	{
		Jpacket packet;
		packet.val["cmd"] = SERVER_DISSOLUTION_ROOM_REQ_BC;
		packet.val["init_uid"] = player->uid;
		packet.val["init_nick_name"] = player->nick_name;
		packet.val["roomid"] = roomid;
		GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_REQ_BC.\n");
		packet.end();
		broadcast(NULL, packet.tostring());
		ev_timer_start(YXJMJ_CONF._loop, &dissolution_confirm_timer);
	}
	return 0;
}

int Room::handler_player_dissolution_room_confirm(Player *player)
{
	
	Json::Value &val = player->client->packet.tojson();
	int confirm = val["confirm"].asInt();

	if (player->agree_dissroom == 1)
	{
		GAME_LOG.error("dissolution_room_req player can not confirm.\n");
		return -1;
	}
	Jpacket packet;
	packet.val["cmd"] = SERVER_DISSOLUTION_ROOM_CONFIRM_BC;
	packet.val["uid"] = player->uid;
	packet.val["nick_name"] = player->nick_name;
	packet.val["roomid"] = roomid;
	packet.val["confirm"] = confirm;
	GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_CONFIRM_BC.\n");
	packet.end();
	broadcast( NULL, packet.tostring());
	
	if ( confirm == 0 )
	{
		//鎷掔粷
		//鍙戦€佽В鏁ｆ埧闂寸粨鏋滃け璐?
		Jpacket packet;
		packet.val["cmd"] = SERVER_DISSOLUTION_ROOM_RESULT_BC;
		packet.val["roomid"] = roomid;
		packet.val["result"] = 0;
		GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_RESULT_BC.\n");
		packet.end();
		broadcast(NULL, packet.tostring());
		player->agree_dissroom = 3;
		//娓呯悊鍒濆鍊?
		/*
		std::map<int,Player*>::iterator it;
		for (it = players.begin(); it != players.end(); it++)
		{
			Player *p = it->second;
			if ( p == player) p->agree_dissroom = 3;//涓嶅悓鎰?
			p->agree_dissroom = 0; //鏈洖澶?
		}
		*/
		ev_timer_stop(YXJMJ_CONF._loop, &dissolution_confirm_timer);
	}
	else if ( confirm == 1)
	{
		player->agree_dissroom = 2;
		//鍚屾剰
		if ( (player_num == 2 && confirm_cnt() >= 1) 
			|| (player_num == 3 && confirm_cnt() >= 2)
			|| (player_num == 4 && confirm_cnt() >= 2) )
		{
			//澶勭悊瑙ｆ暎鎴块棿
			do_dissolution_room();
		}
	}
	return 0;
}

int Room::confirm_cnt()
{
	int cnt = 0;
	std::map<int, Player *>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if (p->agree_dissroom == 2)
		{
			cnt++;
		}
	}
	return cnt;
}

int Room::if_dissolution()
{
	std::map<int, Player *>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p  = it->second;
		if (p->agree_dissroom == 1)
		{
			return 1;
		}
	}
	return 0;
}

int Room::do_dissolution_room()
{
	if (state == STATE_READY && rest_board == board_choose)
	{
		update_room_ticket_status(rec_id, 1);
	}
	if (YXJMJ_CONF._game_flag > 1000000)
	{
		GAME_LOG.error("only kaifang room can do_dissolution_room room.\n");
		return -1;
	}
	
	ev_timer_stop(YXJMJ_CONF._loop, &dissolution_confirm_timer);

	std::map<int,Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		p->agree_dissroom = 0;
	}

	if ( (int) (players.size()) >= player_num)
	{
		send_all_end_info();
	}
	
	Jpacket packet;
	packet.val["cmd"] = SERVER_DISSOLUTION_ROOM_RESULT_BC;
	packet.val["roomid"] = roomid;
	packet.val["result"] = 1;
	if (YXJMJ_CONF._game_flag < 1000000 
		&& state == STATE_READY 
		&& clubid == 0
		&& isdissolution == 1)
	{
		packet.val["uid"] = seats[0].player->uid;
		packet.val["ticket_id"] = rec_id;
	}
	GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_RESULT_BC1.\n");
	packet.end();
	broadcast(NULL, packet.tostring());

	YXJMJ_CONF._server->dissolution_room(roomid);
	return 0;
}

int Room::handler_player_ready(Player *player)
{
	if ( state != STATE_READY )
	{
		GAME_LOG.error("handler_player_ready, player[%d], state[%d] error.", player->uid, state);
		return -1;
	}	
	if ( player->status == READY )
	{
		GAME_LOG.error("handler_player_ready, player[%d], status[%d] error.", player->uid, player->status);
		return -1;
	}
	
	player->status = READY;

	if (_has_timer) 
	{
		player->stop_ready_timer();
	}
	
	Jpacket packet;
	packet.val["cmd"] = SERVER_READY_BC;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	GAME_LOG.debug("SERVER_READY_BC.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	
	int cnt=0;
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *player = it->second;
		if (player->status == READY) 
			cnt++;
	}
	
	if (cnt == player_num)
	{		
		reset();
		start_game();
	}
	
	return 0;
}


bool Room::if_ypsx()
{
	int cnt= 0;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag == true) cnt++;
	}
	if (cnt > 1) 
	{
		return true;
	}
	return false;
}
	

bool Room::outmj_all_check()
{
	for (int i=0; i<player_num-1; i++)
	{
		if ( m_check[i].player_operation == OP_NOT_CHECK)
		{
			return false;
		}
	}
	return true;
}

bool Room:: outmj_ypsx_player_all_check()
{
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag == true && m_check[i].player_operation == OP_NOT_CHECK )
		{
			return false;
		}
	}
	return true;
}

bool Room::outmj_ypsx_player_check_has_hu()
{
	
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag == true && m_check[i].player_operation == OP_HU)
		{
			return true;
		}
	}
	return false;
}


bool Room::outmj_all_pass()
{
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player_operation != OP_PASS)
		{
			return false;
		}
	}
	return true;
}

bool Room::outmj_hu_player_all_pass()
{
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag == true && m_check[i].player_operation != OP_PASS)
		{
			return false;
		}
	}
	return true;
}



int Room::cardtype_to_base_score(int card_type)
{
	/*
	enum CARD_TYPE {
		CARD_TYPE_ERROR = 0,     //无牌型
		CARD_TYPE_PINGHU =  1,   //平胡，1
		CARD_TYPE_DADUIZI = 2,   //大对子 (碰碰胡)，5
		CARD_TYPE_QIDUI   = 3,   //七对   (七小对)，10
		CARD_TYPE_QINGYISE = 4,  //清一色 ，10
		CARD_TYPE_DANDIAO = 5,   //单调，10	
		CARD_TYPE_DI_TING = 6, //地听，10	
		CARD_TYPE_QINGDADUI = 7, //清大对 (清一色碰碰胡)，15		
		CARD_TYPE_DANDIAOQINGYISE = 8, //单调清一色，20
		CARD_TYPE_TIAN_TING = 9,//天听，20
		CARD_TYPE_LONGQIDUI = 10, //龙七对 (豪华七对)，20
		CARD_TYPE_QINGQIDUI = 11, //清七对 (清一色七小对)，20
		CARD_TYPE_TIANHU = 12, //天胡，20
		CARD_TYPE_DIHU = 13, //地胡，20
		CARD_TYPE_SHA_BAO = 14, //杀报 
		CARD_TYPE_QINGLONGBEI = 15, //清龙背 (清一色 豪华七对)，30
	};
	*/
// 	static map<int, int> card_type_score =
// 	{
// 		{ CARD_TYPE_PINGHU,1 },
// 		{ CARD_TYPE_DADUIZI,5 },
// 		{ CARD_TYPE_QIDUI,10 },
// 		{ CARD_TYPE_LONGQIDUI,20 },
// 		{ CARD_TYPE_QINGYISE,10 },
// 		{ CARD_TYPE_QINGDADUI,15 },
// 		{ CARD_TYPE_QINGQIDUI,20 },
// 		{ CARD_TYPE_QINGLONGBEI,30 },
// 		{ CARD_TYPE_DANDIAO,10 },
// 		{ CARD_TYPE_DANDIAOQINGYISE,20 },
// 		{ CARD_TYPE_TIANHU,20 },
// 		{ CARD_TYPE_DIHU,20 },
// 		{ CARD_TYPE_TIAN_TING,20 },
// 		{ CARD_TYPE_DI_TING,10 }
// 	};

	int base_score = 0;
	if (card_type == CARD_TYPE_ERROR)
	{
		GAME_LOG.fatal("card_type_ERROR.\n");
	}
// 	auto it = card_type_score.find(card_type);
// 	if (it != card_type_score.end())
// 	{
// 		base_score = it->second;
// 	}
	else if (card_type == CARD_TYPE_PINGHU ){ //平胡 1倍
		base_score = 1;
	}
	else if (card_type == CARD_TYPE_DADUIZI){ //大对子 5倍
		base_score = 5;
	}
	else if (card_type == CARD_TYPE_QIDUI){//七对 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_LONGQIDUI){//龙七对 20倍
		base_score = 20;
	} 
	else if (card_type == CARD_TYPE_QINGYISE) {//清一色 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_QINGDADUI) {//清大对 15倍
		base_score = 15;
	}
	else if (card_type == CARD_TYPE_QINGQIDUI) {//清七对 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_QINGLONGBEI) {//清龙背 30倍
		base_score = 30;
	}
	else if (card_type == CARD_TYPE_DANDIAO ) {//单吊 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_DANDIAOQINGYISE ) {//单调清一色 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_TIANHU) { //天胡 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_DIHU ) { //地胡 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_TIAN_TING) {//天听 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_DI_TING) { //地听 10 倍
	    base_score = 10;
	}

	return base_score;
}

void Room::calculate_cardtype_score(int card_type, Player *mo_player, Player *fangpao_player, Player* jiepao_player)
{

	int base_score = cardtype_to_base_score(card_type);
	
	if (end_type == ET_ZI_MO) //自摸
	{
		std::map<int, Player*>::iterator it;
		for (it = players.begin(); it != players.end(); it++) 
		{
			Player *p = it->second;
			if (p == mo_player) continue;
			else
			{
				if (p->cur_baoting_flag == 1)//出现杀报 1是天听标识
				{
					p->card_type = CARD_TYPE_SHA_BAO;
					if (p->seatid == banker_seat) //杀天听
					{
						int add_score = 0;
						if (base_score < 20) add_score = 20;
						else add_score = base_score;
						
						p->cardtype_score += -(add_score+1);
						mo_player->cardtype_score += (add_score+1);
					}
					else if (p->seatid != banker_seat) //杀地听
					{
						int add_score = 0;
						if (base_score < 10) add_score = 10;
						else add_score = base_score;

						p->cardtype_score += -(add_score+1);
						mo_player->cardtype_score += (add_score+1);
					}
				}
				else //正常模式
				{
					p->cardtype_score = -(1+base_score);
					mo_player->cardtype_score += (1+base_score);
				}
			}
		}		
	}
	else if (end_type == ET_GANG_KAI_ZI_MO) //杠开
	{
		std::map<int, Player*>::iterator it;
		for (it = players.begin(); it != players.end(); it++) 
		{
			Player *p = it->second;
			if (p == mo_player) continue;
			else
			{
				if (p->cur_baoting_flag == 1)//出现杀报
				{
					p->card_type = CARD_TYPE_SHA_BAO;
					if (p->seatid == banker_seat) //杀天听
					{
						int add_score = 0;
						if (base_score < 20) add_score = 20;
						else add_score = base_score;
						
						p->cardtype_score += -(add_score+2);
						mo_player->cardtype_score += (add_score+2);
					}
					else if (p->seatid != banker_seat) //杀地听
					{
						int add_score = 0;
						if (base_score < 10) add_score = 10;
						else add_score = base_score;

						p->cardtype_score += -(add_score+2);
						mo_player->cardtype_score += (add_score+2);
					}
				}
				else //正常模式
				{
					p->cardtype_score = -(2+base_score);
					mo_player->cardtype_score += (2+base_score);
				}
			}
			
		}
	}
	else if (end_type == ET_FANG_PAO) //放炮
	{     
		if (fangpao_player->cur_baoting_flag == 1)//出现杀报
		{
			fangpao_player->card_type = CARD_TYPE_SHA_BAO;
			if (fangpao_player->seatid == banker_seat)
			{
				if (base_score < 20) base_score = 20;
				fangpao_player->cardtype_score += -base_score;
				jiepao_player->cardtype_score += base_score;
			}
			else if (fangpao_player->seatid != banker_seat)
			{
				if (base_score < 10) base_score = 10;
				fangpao_player->cardtype_score += -base_score;
				jiepao_player->cardtype_score += base_score;
			}
		}
		else//正常模式
		{
			fangpao_player->cardtype_score += -base_score;
			jiepao_player->cardtype_score += base_score;
		}
	}
	else if (end_type == ET_FANG_RE_PAO) //放热炮
	{
		fangpao_player->cardtype_score += -(base_score+2);
		jiepao_player->cardtype_score += (base_score+2);
	}
	else if (end_type == ET_QIANG_GANG) //抢杠胡
	{
		fangpao_player->cardtype_score += -(base_score+1);
		jiepao_player->cardtype_score += (base_score+1);
	}

}


void Room::do_fangpaiji()//番牌鸡
{
	if ( !comm_mjs.pop_mj(fangpaiji_mj) )
	{
		GAME_LOG.debug("do_fangpaiji, no more mjs.\n");
		//没有牌了，所以鸡牌都不算
		std::map<int, Player*>::iterator it;
		for (it = players.begin(); it != players.end(); it++)
		{
			Player *p = it->second;
			p->fangpaiji_num = 0;
		}
	}
	else
	{
		
		std::map<int, Player*>::iterator it;
		for (it = players.begin(); it != players.end(); it++)
		{
			Player *p = it->second;
			if ( (end_type == ET_FANG_RE_PAO && cur_outmj_player == p)
				|| (end_type == ET_QIANG_GANG && cur_qgh_player == p))//放热炮者不计算翻牌鸡
			{
				GAME_LOG.debug("----------re pao, qiang gang , not calculate fangpaiji-------------p->uid[%d].\n",p->uid);
				p->fangpaiji_num = 0;
			}
			else
			{
				p->fangpaiji_num = p->calculate_fangpaiji_base_num(fangpaiji_mj);
			}
		}
	}
	//当一个人每有一个鸡分 所有人都要给这个人一分
	std::map<int, Player*>::iterator it1;
	for (it1 = players.begin(); it1 != players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2=players.begin(); it2 != players.end(); it2++ ) 
		{
			Player *p2 = it2->second;
			if (p2 == p)
			{
				p->fangpaiji_score += p2->fangpaiji_num * (player_num - 1);
			}
			else
			{
				p->fangpaiji_score -= p2->fangpaiji_num;
			}
		}
	}
}

void Room::do_gudingji() //固定鸡
{
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( (end_type == ET_FANG_RE_PAO && cur_outmj_player == p && cur_outmj_player->jiaopai_flag == 1)
			|| (end_type == ET_QIANG_GANG && cur_qgh_player == p && cur_outmj_player->jiaopai_flag == 1))//放热炮者不计算固定鸡且叫牌玩家
		{
			GAME_LOG.debug("----------re pao, qiang gang , not calculate gudingji-------------p->uid[%d].\n", p->uid);
			p->gudingji_num_hole = 0;
			p->gudingji_num_out = 0;
		}		
		else if ( (end_type == ET_FANG_RE_PAO && cur_outmj_player == p && cur_outmj_player->jiaopai_flag == 0)
		|| (end_type == ET_QIANG_GANG && cur_qgh_player == p && cur_outmj_player->jiaopai_flag == 0))//放热炮者不计算固定鸡且叫牌玩家
		{
			p->gudingji_num_hole = 0;
			p->gudingji_num_out = p->calculate_gudingji_base_num_out();
		}
		else
		{
			p->gudingji_num_hole = p->calculate_gudingji_base_num_hole();
			p->gudingji_num_out = p->calculate_gudingji_base_num_out();
		}
	}

	std::map<int, Player*>::iterator it1;
	for (it1 = players.begin(); it1 != players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2=players.begin(); it2 != players.end(); it2++ ) 
		{
			Player *p2 = it2->second;
			if (p == p2)
			{
				continue;				
			}
			else
			{
				
				p->gudingji_score += p->gudingji_num_hole;
 				p2->gudingji_score -= p->gudingji_num_hole;				

 				if (p->gudingji_num_out >= 0) 
				{					
					p->gudingji_score += p->gudingji_num_out;
					p2->gudingji_score -= p->gudingji_num_out;		
				}
				else if (p->gudingji_num_out < 0 && p2->jiaopai_flag == 1)
				{
					
					p->gudingji_score += p->gudingji_num_out;
					p2->gudingji_score -= p->gudingji_num_out;				
				}
			}
		}
	}
}

void Room::do_chongfengji()
{
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( (end_type == ET_FANG_RE_PAO && cur_outmj_player == p && cur_outmj_player->jiaopai_flag == 1)
			|| (end_type == ET_QIANG_GANG && cur_qgh_player == p && cur_outmj_player->jiaopai_flag == 1))//放热炮者不计算冲锋鸡
		{
			GAME_LOG.debug("----------re pao, qiang gang , jiaopai, not calculate chongfengji-------------p->uid[%d].\n", p->uid);
			p->chongfengji_num = 0;
		}
		else
		{
			p->chongfengji_num = p->calculate_chongfengji_base();
		}
	}

	std::map<int, Player*>::iterator it1;
	for (it1 = players.begin(); it1 != players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2=players.begin(); it2 != players.end(); it2++ ) 
		{
			Player *p2 = it2->second;
			if (p == p2)
			{
				continue;
 			}
			else
			{
				if (p->chongfengji_num > 0)
				{					
					p->chongfengji_score += p->chongfengji_num * 2;
					p2->chongfengji_score -= p->chongfengji_num *2;
				}
				else if (p->chongfengji_num < 0 && p2->jiaopai_flag == 1)
				{
					p->chongfengji_score += p->chongfengji_num * 2;
					p2->chongfengji_score -= p->chongfengji_num *2;
				}
			}
		}
	}
}

void Room::do_zherenji()
{
	if (zherenji_from_player != NULL && zherenji_to_player != NULL)
	{
		GAME_LOG.debug(" has zherenji.\n ");
		if (zherenji_to_player->jiaopai_flag == 1)
		{
			std::map<int, Player*>::iterator it;
			for (it = players.begin(); it != players.end(); it++)
			{
				Player *p = it->second;
				if ( p == zherenji_to_player ) 
				{
					zherenji_to_player->zherenji_score += ( (player_num-1)*zherenji_type + 1 );
				}
				else
				{
					p->zherenji_score -= zherenji_type;
					if (p == zherenji_from_player)
					{
						p->zherenji_score -= 1;
					}
				}
			}
		}
		else if (zherenji_to_player->jiaopai_flag == 0)
		{
			std::map<int, Player*>::iterator it;
			for (it = players.begin(); it != players.end(); it++)
			{
				Player *p = it->second;
				if ( p == zherenji_to_player ) 
				{
					continue;
				}
				else
				{
					if (p->jiaopai_flag == 1)
					{
						p->zherenji_score += zherenji_type;
						zherenji_to_player ->zherenji_score -= zherenji_type;
						
						if (p == zherenji_from_player)
						{
							p->zherenji_score += 1;
							zherenji_to_player->zherenji_score -= 1;
						}
					}
				}
			}
		}
	}
}


void Room:: calculate_total_winlose_score()
{
	do_gang_score(); //计算杠分
	do_fangpaiji();//番牌鸡
	do_gudingji(); //计算固定鸡
	do_chongfengji(); //计算冲锋鸡
	do_zherenji(); //计算责任鸡

	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		p->winlose_score = p->cardtype_score + p->gudingji_score + p->fangpaiji_score + p->chongfengji_score + p->zherenji_score +p->cur_gang_score;
		p->score = p->score + p->winlose_score;
	}
}

void Room::do_gang_score()
{
	std::map<int, Player*>::iterator it;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *player = it->second;
		if (player->jiaopai_flag == 1)
		{
			for (unsigned int i = 0; i< player->form_mjs.form_mjz.size(); i++ )
			{
			
				if (end_type == ET_FANG_RE_PAO && cur_outmj_player == player && i== (player->form_mjs.form_mjz.size()-1) )
				{					
					//如果出现了热炮的情况 (杠上炮), 放炮玩家的最后那个杠不算
					continue;
				}
				//放杠 谁放的杠谁给3分
				if (player->form_mjs.form_mjz[i].zu_type == FANG_GANG)
				{
					player->cur_gang_score += 3;
					player->cur_fanggang_score += 3;
					int from_seat = player->form_mjs.form_mjz[i].from_seat;
					seats[from_seat].player->cur_gang_score -=3;
					seats[from_seat].player->cur_fanggang_score -=3;
					
				}
				//明杠 所有其他人给3分
				else if (player->form_mjs.form_mjz[i].zu_type == MING_GANG)
				{
					player->cur_gang_score += (player_num-1)*3;
					player->cur_minggang_score += (player_num-1)*3;
					for (int i=0; i<player_num; i++)
					{
						if (seats[i].player != player)
						{
							seats[i].player->cur_gang_score -= 3;
							seats[i].player->cur_minggang_score -= 3;
						}
					}
				}
				//暗杠 所有其它人给3分
				else if (player->form_mjs.form_mjz[i].zu_type == ANG_GANG)
				{
					player->cur_gang_score += (player_num-1)*3;
					player->cur_angang_score += (player_num-1)*3;
					for (int i=0; i<player_num; i++)
					{
						if (seats[i].player != player)
						{
							seats[i].player->cur_gang_score -= 3;
							seats[i].player->cur_angang_score -= 3;
						}
					}
				}
			}
		}
	}
}

void Room::do_huangzhuang()
{

	end_type = ET_HUANG_ZHUANG;
	/*
    a.查牌后，（各玩家均未叫牌），则各家无输赢，庄家连庄。
    b.查牌后，四家都叫牌，则各家无输赢，庄家连庄。
    c.查牌后，有人叫牌，有人不叫牌。叫牌者根据所叫牌算分，不叫牌者需要分别给每个叫牌者相应的分数。在叫牌者中，有庄家则连庄。没庄家则离庄家最近的下家接庄。
    d.特殊情况，3家叫牌，一家未叫。未叫者付3家，且未叫者接庄。
	*/

	//计算叫牌
	std::map<int, Player*>::iterator it;
	for ( it = players.begin(); it!=players.end(); it++ )
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}
	
	int cnt = 0;
	for ( it = players.begin(); it!=players.end(); it++ )
	{
		Player *p = it->second;
		if (p->jiaopai_flag == 1)
		{
			cnt++;
		}
	}
	
	if ( cnt == 0 ) //a.查牌后，（各玩家均未叫牌），则各家无输赢，庄家连庄。
	{
		next_banker_seat = banker_seat;
	}
	else if (cnt == player_num ) //b.查牌后，四家都叫牌，则各家无输赢，庄家连庄。
	{
		next_banker_seat = banker_seat;
	}
	else if (cnt == player_num-1 && player_num > 2) // d.特殊情况，其他家都叫牌，一家未叫。未叫者付3家，且未叫者接庄。
	{
		//确认下一局庄家
		for (it=players.begin(); it != players.end(); it++)
		{
			Player *p = it->second;
			if (p->jiaopai_flag == 0)
			{
				next_banker_seat = p->seatid;
			}
		}

		//未叫牌向叫牌玩家付钱
		//logic
		std::map<int, Player*>::iterator it1;
		for(it1 = players.begin(); it1 != players.end(); it1++) //未叫牌者循环
		{
			Player *p1 = it1->second;
			if (p1->jiaopai_flag == 1) continue;
			//排除去叫牌的下面都是没叫牌的
			
			std::map<int, Player*>::iterator it2;
			for (it2 = players.begin(); it2 != players.end(); it2++) //叫牌者循环
			{
				Player *p2 = it2->second;
				if (p2->jiaopai_flag == 0) continue; 
				//排除去没叫牌的下面都是叫牌的
				//计算叫牌玩家牌型
				p2->card_type = calculate_jiaopai_card_type(p2);

				int temp_score = cardtype_to_base_score(p2->card_type);
				
				p2->cardtype_score += temp_score;
				p1->cardtype_score -= temp_score;
				
			}	
		}		
	}
	else //c.查牌后，有人叫牌，有人不叫牌。叫牌者根据所叫牌算分，不叫牌者需要分别给每个叫牌者相应的分数。在叫牌者中，有庄家则连庄。没庄家则离庄家最近的下家接庄。
	{
		//确认下一局庄家
		next_banker_seat = -1;
		for ( it=players.begin(); it != players.end(); it++ )
		{
			Player *p = it->second;
			if (p->jiaopai_flag == 1 && p->seatid == banker_seat )
			{
				next_banker_seat = p->seatid;
			}
		}
		if (next_banker_seat == -1)
		{
			Player *jp_player = NULL;
			jp_player = next_jiaopai_player(seats[banker_seat].player);
			if (jp_player == NULL)
			{
				next_banker_seat = next_player(seats[banker_seat].player)->seatid;
			}
			else
			{
				next_banker_seat = jp_player->seatid;
			}
		}

		//未叫牌向叫牌玩家付钱
		//logic
		std::map<int, Player*>::iterator it1;
		for(it1 = players.begin(); it1 != players.end(); it1++) //未叫牌者循环
		{
			Player *p1 = it1->second;
			if (p1->jiaopai_flag == 1) continue;
			//排除去叫牌的下面都是没叫牌的
			
			std::map<int, Player*>::iterator it2;
			for (it2 = players.begin(); it2 != players.end(); it2++) //叫牌者循环
			{
				Player *p2 = it2->second;
				if (p2->jiaopai_flag == 0) continue; 
				//排除去没叫牌的下面都是叫牌的
				//计算叫牌玩家牌型
				p2->card_type = calculate_jiaopai_card_type(p2);

				int temp_score = cardtype_to_base_score(p2->card_type);
				
				p2->cardtype_score += temp_score;
				p1->cardtype_score -= temp_score;
				
			}	
		}
	
	}

	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		p->winlose_score = p->cardtype_score;
		p->score = p->score + p->winlose_score;
	}
	
}

int Room::game_end(int type)
{
	state = STATE_END;
	GAME_LOG.info("------------now game end----------------.\n");

	Jpacket packet;
	packet.val["cmd"] = SERVER_GAME_END_BC;
	packet.val["roomid"] = roomid;	
	packet.val["board_choose"] = board_choose;
	packet.val["player_num"] = player_num;
	packet.val["cur_board"] = board_choose - rest_board;
	std::string time_str = general_time_str();
	packet.val["time_str"] = time_str.c_str();
	packet.val["end_type"] = end_type;
	packet.val["fangpaiji_mj"] = fangpaiji_mj.val;
	if (fangpaiji_mj.val != 0)
	{
		packet.val["fangpaiji_mj_next"] = fangpaiji_mj.next_fangpai_mj().val;
	}
	else
	{
		packet.val["fangpaiji_mj_next"] = 0;
	}


	packet.val["game_flag"] = YXJMJ_CONF._game_flag;
	if (YXJMJ_CONF._game_flag  > 1000000)
	{
		packet.val["base_gold"] = base_gold;
	}

	std::map<int, Player*>::iterator it;
	int i=0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		packet.val["players"][i]["uid"] = p->uid;
		packet.val["players"][i]["nick_name"] = p->nick_name;
		packet.val["players"][i]["avater_url"] = p->avater_url;
		packet.val["players"][i]["seatid"] = p->seatid;
		packet.val["players"][i]["jiaopai_flag"] = p->jiaopai_flag;
		packet.val["players"][i]["cur_gang_score"] = p->cur_gang_score;
		packet.val["players"][i]["cur_angang_score"] = p->cur_angang_score;
		packet.val["players"][i]["cur_minggang_score"] = p->cur_minggang_score;
		packet.val["players"][i]["cur_fanggang_score"] = p->cur_fanggang_score;	
		packet.val["players"][i]["cur_fangpaiji_score"] = p->fangpaiji_score;
		packet.val["players"][i]["cur_gudingji_score"] = p->gudingji_score;
		packet.val["players"][i]["cur_chongfengji_score"] = p->chongfengji_score;
		packet.val["players"][i]["cur_zherengji_score"] = p->zherenji_score;
		packet.val["players"][i]["cur_cardtype_score"] = p->cardtype_score;		
		//GAME_LOG.debug("uid:%d, base_gold:%d, winlose_score:%d.\n",p->uid, base_gold, p->winlose_score);
		//每日任务完成
		auto task_finish = [&](int uid, string task_id) {
			std::string key;
			std::stringstream strtime;
			auto currenttime = time(NULL);
			char tAll[255];
			strftime(tAll, sizeof(tAll), "%Y-%m-%d", localtime(&currenttime));
			strtime << tAll;
			key = "task_unclaimed_" + task_id + "_" + strtime.str();
			if (0 != Singleton<RedisClient>::Instance()->command("hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1))
			{
				GAME_LOG.error("redis command fail: hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1);
			}
			else
			{
				GAME_LOG.debug("redis command succ: hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1);
			}
		};
		int end_winlose_gold = 0;
		if ( YXJMJ_CONF._game_flag > 1000000)
		{
			//打出一个冲锋鸡任务
			if (p->chongfengji_num > 0)
			{
				task_finish(p->uid, "4");
			}
			//排位单局获得30分的每日任务
			if (YXJMJ_CONF._game_flag == 2000001 && p->winlose_score > 30)
			{
				task_finish(p->uid, "3");
			}
			int num = p->winlose_score;		
			if (p->gold + num * base_gold> 0 )
			{
				end_winlose_gold = num * base_gold;
			}
			else
			{
				end_winlose_gold = p->gold;
			}
			if (p->robot_flag != 1 && YXJMJ_CONF._game_flag != 2000001)
			{
				decrease_gold(p->uid, end_winlose_gold);
			}
			//add paiwei jifen
			if (YXJMJ_CONF._game_flag == 2000001 && p->winlose_score > 0)
			{
				GAME_LOG.debug("uid:%d, add_paiwei_score:%d.\n", p->uid, p->winlose_score);
				decrease_paiwei_score(p->uid, p->winlose_score);				
				insert_paiwei_score_change_rec(p->uid, p->paiwei_score, p->winlose_score, p->paiwei_score+p->winlose_score);				
				p->paiwei_score += p->winlose_score;
				packet.val["players"][i]["cur_add_paiwei_score"] = p->winlose_score;
			}
			if (YXJMJ_CONF._game_flag == 2000001 && p->winlose_score <= 0)
			{
				packet.val["players"][i]["cur_add_paiwei_score"] = 0;
			}
			if (p->robot_flag != 1 )
			{
				if ( YXJMJ_CONF._game_flag != 2000001 )
				{
					insert_gold_change_rec(p->uid, end_winlose_gold, "金币场", "金币场结算输赢");
					p->gold += end_winlose_gold;
				}
			}			
			packet.val["players"][i]["cur_winlose_score"] = num * base_gold;
			p->vec_score.push_back(  num* base_gold );			
		}
		else
		{
			packet.val["players"][i]["cur_winlose_score"] = p->winlose_score;
			p->vec_score.push_back(p->winlose_score);
		}
		
		packet.val["players"][i]["score"] = p->score;
		packet.val["players"][i]["cur_end_flag"] = p->cur_end_flag;
		packet.val["players"][i]["cur_pao_flag"] = p->cur_pao_flag;

		if ( end_type == ET_HUANG_ZHUANG )
		{	
			packet.val["players"][i]["card_type"] = CARD_TYPE_ERROR; 
		} 
		else
		{
		                                                                           
			packet.val["players"][i]["card_type"] = p->card_type; 
		}
			packet.val["players"][i]["fangpaiji_num"] = p->fangpaiji_num;
		packet.val["players"][i]["gudingji_num_hole"] = p->gudingji_num_hole;
		packet.val["players"][i]["gudingji_num_out"] = p->gudingji_num_out;
		packet.val["players"][i]["chongfengji_num"] = p->chongfengji_num;
		packet.val["players"][i]["gold"] = p->gold;
		packet.val["players"][i]["diamonds"] = p->diamonds;
		packet.val["players"][i]["paiwei_score"] = p->paiwei_score;

		int if_banker = 0;
		if (p->seatid == banker_seat)
		{
			if_banker = 1;
		}
		else
		{
			if_banker = 0;
		}
		packet.val["players"][i]["if_banker"] = if_banker;
	
		std::string hole_str;
		for (unsigned int j=0; j<p->hole_mjs.mjs.size(); j++)
		{
			packet.val["players"][i]["hole_mjs"].append(p->hole_mjs.mjs[j].val);
			hole_str += i2str(p->hole_mjs.mjs[j].val);
			if (j < p->hole_mjs.mjs.size() - 1)
			{
				hole_str += ",";
			}
		}
		if ( p->hole_mjs.mjs.size() == 0)
		{
			packet.val["players"][i]["hole_mjs"].resize(0);
		}
		
		std::string fm_str;
		for (unsigned int j=0; j< p->form_mjs.form_mjz.size(); j++)
		{
			MJZ mjz = p->form_mjs.form_mjz[j];			
			packet.val["players"][i]["form_mjs"][j]["zu_type"] = mjz.zu_type;
			packet.val["players"][i]["form_mjs"][j]["from_seat"] = mjz.from_seat;
			fm_str += i2str(mjz.zu_type);
			fm_str += ":";
			for (unsigned int k=0; k<mjz.zu_mjs.size(); k++)
			{
				packet.val["players"][i]["form_mjs"][j]["zu_mjs"].append(mjz.zu_mjs[k].val);
				fm_str += i2str(mjz.zu_mjs[k].val);
				if (k < mjz.zu_mjs.size() -1)
				{
					fm_str += ",";
				}
			}			
			if ( j < p->form_mjs.form_mjz.size() - 1 )
			{
				fm_str += "|";			
			}
		}
		if ( p->form_mjs.form_mjz.size() == 0 )
		{
			packet.val["players"][i]["form_mjs"].resize(0);	
		}
		std::string out_str;
		for (unsigned int j=0; j< p->out_mjs.mjs.size(); j++)
		{
			packet.val["players"][i]["out_mjs"].append(p->out_mjs.mjs[j].val);
			out_str += i2str(p->out_mjs.mjs[j].val);
			if (j < p->out_mjs.mjs.size() -1)
			{
				out_str += ",";
			}
		}
		
		if (p->out_mjs.mjs.size() == 0)
		{
			packet.val["players"][i]["out_mjs"].resize(0);
		}

		if (YXJMJ_CONF._game_flag / 1000000 == 1)
		{
			if (end_winlose_gold > 0)
			{
				increase_user_result(p->uid, 1);
			}
			else if (end_winlose_gold < 0)
			{
				increase_user_result(p->uid, 2);
			}
			else
			{
				increase_user_result(p->uid, 3);
			}
		}

		if (YXJMJ_CONF._game_flag < 1000000)
		{
			insert_board_end_record(
				rec_id,
				roomid,
				board_choose,
				board_choose - rest_board,
				player_num,
				time_str,
				end_type,
				fangpaiji_mj.val,
				fangpaiji_mj.next_fangpai_mj().val,
				p->uid,
				p->nick_name,
				p->seatid,
				if_banker,
				p->jiaopai_flag,
				p->cur_gang_score,
				p->cur_angang_score,
				p->cur_minggang_score,
				p->cur_fanggang_score,
				p->fangpaiji_score,
				p->gudingji_score,
				p->chongfengji_score,
				p->zherenji_score,
				p->cardtype_score,
				p->winlose_score,
				p->score,
				p->cur_pao_flag,
				p->card_type,
				p->fangpaiji_num,
				hole_str,
				fm_str,
				out_str
			);
		}
		
		i++;
	}
	GAME_LOG.debug("SERVER_GAME_END_BC.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	//统计服务器当天游戏数量
	string date = general_date_str();
	increase_add_action(YXJMJ_CONF._server_id, date);

	if (YXJMJ_CONF._game_flag < 1000000)
	{
		int end_board = board_choose - rest_board;
		if (rec_id > 0 && player_num == 2)
		{
			update_total_end_record(rec_id,end_board,time_str,seats[0].player->score-1000,seats[1].player->score-1000);
		}
		else if (rec_id > 0 && player_num == 3) 
		{
			update_total_end_record(rec_id,end_board,time_str,seats[0].player->score-1000,seats[1].player->score-1000,seats[2].player->score-1000);
		}
		else if (rec_id > 0 && player_num == 4)
		{
			update_total_end_record(rec_id,end_board,time_str,seats[0].player->score-1000,seats[1].player->score-1000,seats[2].player->score-1000,seats[3].player->score-1000);
		}
	}
	
	ev_timer_start(YXJMJ_CONF._loop, &end_flash_timer);
		
	return 0;
}

int Room::getin_mj(Player *cur_player, int type)
{
	Mj mj;
	//没有牌了的荒庄处理
	if ( !comm_mjs.pop_mj(mj) )
	{
		GAME_LOG.info("comm mjs, has no more mj.\n");
		do_huangzhuang();
		game_end(1);
		return 1;
	}
	
	cur_player->hole_mjs.add_mj(mj);
	cur_player->mo_mj = mj;
	cur_player->mo_cnt++;
	cur_player->guo_shou_bu_hu_flag = 0;

	//涓変釜鐜╁閲嶆柊缃帺瀹剁姸鎬侊紝鎽哥墝鐨勭帺瀹剁疆涓篒NPLAY_WAIT_OPT(鍦ㄦ父鎴忎腑杞埌鎿嶄綔杩樻病鎿嶄綔),鍏朵粬鐜╁缃负INPLAY(鍦ㄦ父鎴忎腑娌¤疆鍒版搷浣?
	//刷新各个用户的状态
	cur_player->status = INPLAY_AFTER_GETIN_MJ;
	std::map<int,Player*>::iterator it;
	for (it=players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		if ( p == cur_player) continue;
		p->status = INPlAY;
	}

	if (type == 1) gang_mo_cnt ++;

	//广播摸到的牌？
	Jpacket packet;
	packet.val["cmd"] = SERVER_GET_ONE_MJ;
	packet.val["uid"] = cur_player->uid;
	packet.val["seatid"] = cur_player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["rest_mjs"] = comm_mjs.count();	
	packet.val["mj"] = mj.val;	
	packet.val["mo_type"] = type;
	GAME_LOG.debug("SERVER_GET_ONE_MJ.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	
	
	return 0;		
}

int Room::operate_check_after_getin_mj( Player *cur_player)
{
	//这个时候是在用户摸得一张牌之后的判断	
	int ming_gang_flag = 0;
	int an_gang_flag = 0;	
	std::vector<int> vec_gang_mj;
	int ting_flag = 0;
	std::vector<int> vec_ting_mj;
	int zi_mo_hu_flag = 0;

	zi_mo_hu_flag = (int)(check_zi_mo_hu(cur_player)); 

	if (cur_player->cur_baoting_flag == 0)
	{
		ming_gang_flag = (int)(check_ming_gang(cur_player, cur_player->mo_mj));			
		an_gang_flag = (int)(check_ang_gang(cur_player, vec_gang_mj));	
		ting_flag = (int)(check_op_ting(cur_player, vec_ting_mj));
	}

	//如果玩家已经亮牌，那么直接摸牌胡牌，或者，出掉摸取的牌。
	if ((cur_player->cur_baoting_flag == 1 || cur_player->cur_baoting_flag == 2)&& ! zi_mo_hu_flag)
	{
		cur_player->start_auto_outmj_timer(); //定时器，延时一秒出
		return 0;
	}

	if (cur_player->robot_op == 1)
	{
		cur_player->start_auto_outmj_timer();
		return 0;
	}

	//告诉这个刚摸了牌的用户 他可以进行哪些操作
	//褰撳彲浠ユ湁鎿嶄綔鏃讹紝涓嬪彂鎻愮ず鎿嶄綔
	Jpacket packet;
	packet.val["cmd"] = SERVER_OPERATE_CHECK_AFTER_GETIN_MJ;
	packet.val["uid"] = cur_player->uid;
	packet.val["seatid"] = cur_player->seatid;
	packet.val["roomid"] = roomid;	
	packet.val["ming_gang_flag"] = ming_gang_flag;
	packet.val["getin_mj"] = cur_player->mo_mj.val;		
	packet.val["an_gang_flag"] = an_gang_flag;	
	packet.val["zi_mo_hu_flag"] = zi_mo_hu_flag;
	packet.val["ting_flag"] = ting_flag;
	
	if (an_gang_flag != 0)
	{
		for (unsigned int i=0; i<vec_gang_mj.size(); i++)
		{
			packet.val["an_gang_mj_choose"].append(vec_gang_mj[i]);  
		}
	}
	
	if (ting_flag != 0)
	{
		for (unsigned int i=0; i<vec_ting_mj.size(); i++)
		{
			packet.val["ting_mj_choose"].append(vec_ting_mj[i]);  
		}
	}

	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_GETIN_MJ.\n");
	packet.end();
	unicast(cur_player, packet.tostring());
	
	if (_has_timer)
	{
		cur_getin_player = cur_player;
		cur_getin_mj = cur_player->mo_mj;
		cur_player->start_getin_outmj_timer();
	}

	
	return 0;
	
}

int Room::operate_check_after_peng_mj(Player *player)
{
	//鏄惁鑳戒寒鍊掑垽鏂?
	int an_gang_flag = 0;
	
	std::vector<int> vec_gang_val;
	if ( check_ang_gang(player, vec_gang_val) )
	{
		an_gang_flag = 1;	
	}
	Jpacket packet;
	packet.val["cmd"] = SERVER_OPERATE_CHECK_AFTER_PENG;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["an_gang_flag"] = an_gang_flag;

	if (an_gang_flag == 1)
	{
		for (unsigned int i=0; i<vec_gang_val.size(); i++)
		{
			packet.val["an_gang_mj_choose"].append(vec_gang_val[i]);
		}
	}
	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_PENG.\n");
	packet.end();
	unicast(player, packet.tostring());

	if (_has_timer)
	{
		player->start_getin_outmj_timer();
	}
	return 0;
}


int Room::operate_check_qiang_gang_hu(Mj gang_mj, Player* gang_player)
{
	int ret = 0;
	for (int i=0; i<player_num-1; i++)
	{
		int flag =check_qiang_gang_hu( m_check_qgh[i].player, gang_mj, gang_player);
		m_check_qgh[i].qianggang_hu_flag = 	flag;
		if ( !flag )
		{
			m_check_qgh[i].player_operation = OP_PASS;
		}
		else
		{
			//通知用户可以抢杠胡
			send_bar_operate_check_qiang_gang_hu(m_check_qgh[i].player, gang_mj);
			m_check_qgh[i].player->start_qiangganghu_timer();
			ret = 1;
			//抢杠胡谁按得快就是谁？全通知了？
		}
	}
	return ret;	
}

/*
int Room::outmj_operater_check()
{

	int hu_num = 0;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag) hu_num++;
	}
	if (hu_num > 1 && )

	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag == true && m_check[i].send_hu_flag == false) 
		{	
			goto DO_CHECK_SEND_OP:
		}
		if (m_check[i].fang_gang_flag == true && m_check[i].send_gang_flag == false)
		{
			goto DO_CHECK_SEND_OP:
		}
		if (m_check[i].peng_flag == true && m_check[i].send_peng_flag == false)
		{
			goto DO_CHECK_SEND_OP:
		}
	}
	
	return 1;


DO_CHECK_SEND_OP:
	
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == NULL) continue;
		if (m_check[i].fangpao_hu_flag == true && m_check[i].send_hu_flag == false)
		{
			if ( hu_num == 1 )
			{
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);
				m_check[i].send_hu_flag = true;
				m_check[i].send_gang_flag = true;
				m_check[i].send_peng_flag = true;
			}
			else
			{				
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, 0,0);
				m_check[i].send_hu_flag = true;				
			}
			return 0;
		}
	}

	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == NULL) continue;
		if (m_check[i].fang_gang_flag == true && m_check[i].send_gang_flag == false)
		{		
			send_bar_operate_check_after_putout_mj(m_check[i].player, 0, m_check[i].fang_gang_flag, m_check[i].peng_flag);
			m_check[i].send_gang_flag = true;
			m_check[i].send_peng_flag = true;
			return 0;
		}
	}

	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == NULL) continue;
		if (m_check[i].peng_flag == true && m_check[i].send_peng_flag == false)
		{			
			send_bar_operate_check_after_putout_mj(m_check[i].player, 0, 0, m_check[i].peng_flag);
			m_check[i].send_peng_flag = true;
			return 0;
		}
	}
	return 0;
}
*/

int Room::operate_check_after_putout_mj(Mj out_mj, Player *out_mj_player)
{
	//初始化打出牌的玩家可操作检测结构体
	for (int i=0; i<3; i++)
	{
		m_check[i].clear();
	}

	if (player_num == 2)
	{
		Player *p1 = next_player(cur_outmj_player);
		P_CHECK pcheck;
		pcheck.clear();
		pcheck.player = p1;
		m_check[0] = pcheck;	
	}
	else if (player_num == 3)
	{
		Player *p1 = next_player(cur_outmj_player);
		P_CHECK pcheck1;
		pcheck1.clear();
		pcheck1.player = p1;
		m_check[0] = pcheck1;

		Player *p2 = next_player(p1);
		P_CHECK pcheck2;
		pcheck2.clear();
		pcheck2.player = p2;
		m_check[1] = pcheck2;
	}
	else if (player_num == 4)
	{
		Player *p1 = next_player(cur_outmj_player);
		P_CHECK pcheck1;
		pcheck1.clear();
		pcheck1.player = p1;
		m_check[0] = pcheck1;

		Player *p2 = next_player(p1);
		P_CHECK pcheck2;
		pcheck2.clear();
		pcheck2.player = p2;
		m_check[1] = pcheck2;

		Player *p3 = next_player(p2);
		P_CHECK pcheck3;
		pcheck3.clear();
		pcheck3.player = p3;
		m_check[2] = pcheck3;
	}
	
	
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].player == NULL) continue;
		
		m_check[i].fangpao_hu_flag = check_fang_pao_hu(m_check[i].player, out_mj, out_mj_player);
		//如果报听，不能再碰杠
		if (m_check[i].player->cur_baoting_flag != 0)
		{
			m_check[i].fang_gang_flag = 0;
			m_check[i].peng_flag = 0;
		}
		else
		{
			m_check[i].fang_gang_flag = check_fang_gang(m_check[i].player, out_mj);
			m_check[i].peng_flag = check_peng(m_check[i].player, out_mj);
		}
			GAME_LOG.debug("player[%d], fangpao_hu_flag:%d, fang_gang_flag:%d, peng_flag:%d.\n",m_check[i].player->uid, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag,m_check[i].peng_flag);
		
		//没有可操作的直接置位PASS

		if (m_check[i].player->robot_op == 1)
		{
			m_check[i].fangpao_hu_flag  = false;
			m_check[i].fang_gang_flag = false;
			m_check[i].peng_flag = false;	
		}
		
		if ( !m_check[i].fangpao_hu_flag &&  !m_check[i].fang_gang_flag &&  !m_check[i].peng_flag )
		{
			m_check[i].player_operation = OP_PASS;			
			GAME_LOG.debug("pass.\n");
		}

	}

	bool has_hu = false;
	bool has_gang = false;
	bool has_peng = false;
	
	int hu_num = 0;
	for (int i=0; i<player_num-1; i++)
	{
		if (m_check[i].fangpao_hu_flag) hu_num++;
	}
	
	//先看有没有能胡的。
	for ( int i=0; i<player_num-1; i++ )
	{
		if (m_check[i].fangpao_hu_flag)
		{
			//如果只有他一个人可以胡
			if( hu_num <= 1)
			{
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);					
				m_check[i].player->start_pass_timer();
				has_hu = true;
				break;
			}
			else if (hu_num > 1)
			{
				//如果多人可以胡
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, 0, 0);
				m_check[i].player->start_pass_timer();
				has_hu = true;
			}
		}
	}

	if ( ! has_hu )
	{
		for (int i=0; i<player_num-1; i++)
		{
			if (m_check[i].fang_gang_flag)
			{
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);					
				m_check[i].player->start_pass_timer();
				has_gang = true;
				has_peng = true;
				break;
			}
		}
	}

	if ( !has_hu && !has_gang )
	{
		for (int i=0; i<player_num-1; i++)
		{
			if (m_check[i].peng_flag)
			{
				send_bar_operate_check_after_putout_mj(m_check[i].player, m_check[i].fangpao_hu_flag, m_check[i].fang_gang_flag, m_check[i].peng_flag);					
				m_check[i].player->start_pass_timer();
				has_peng = true;
				break;
			}
		}
	}
	
	if ( !has_hu && !has_gang && !has_peng)
	{
		
		cur_seat = next_seat(cur_seat);
		Player *player = seats[cur_seat].player;
		//没人要的牌 变成冲锋鸡
		//冲锋鸡
		if (cur_outmj.val == S1 && chongfengji_player == NULL && zherenji_from_player == NULL)
		{
			chongfengji_player = cur_outmj_player;
			Jpacket packet;
			packet.val["cmd"] = SERVER_CHONG_FENG_JI_BC;
			//packet.val["chongfengji_uid"] = chongfengji_player->uid;
			//packet.val["chongfengji_seat"] = chongfengji_player->seatid;
			packet.val["uid"] = chongfengji_player->uid;
			packet.val["seatid"] = chongfengji_player->seatid;
			GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
			packet.end();
			broadcast(NULL, packet.tostring());
		}
		
		gang_shang_pao_check_flag = 0;
		if ( getin_mj(player) == 1 )
		{
			return 0;
		}
		operate_check_after_getin_mj(player);		
	}

	return 0;
}

int Room::send_bar_operate_check_after_putout_mj(Player *player, int fangpaohu_flag, int fang_gang_flag, int peng_flag)
{
	Jpacket packet;
	packet.val["cmd"] = SERVER_OPERATE_CHECK_OTHERS_PUTOUT_MJ;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["fang_pao_hu_flag"] = fangpaohu_flag;
	packet.val["fang_gang_flag"] = fang_gang_flag;
	packet.val["peng_flag"] = peng_flag;
	GAME_LOG.debug("SERVER_OPERATE_CHECK_OTHERS_PUTOUT_MJ.\n");
	packet.end();
	unicast(player, packet.tostring());
	
	return 0;
}

int Room::send_bar_operate_check_qiang_gang_hu(Player *player, Mj gang_mj)
{
	Jpacket packet;
	packet.val["cmd"] = SERVER_OPERATE_CHECK_QIANG_GANG_HU;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["qgh_mj"] = gang_mj.val;
	GAME_LOG.debug("SERVER_OPERATE_CHECK_QIANG_GANG_HU.\n");
	packet.end();
	unicast(player, packet.tostring());
	return 0;
}

void Room::vector_to_json_array(std::vector<Mj> &mjs, Jpacket &packet, string key)
{
	for (unsigned int i = 0; i < mjs.size(); i++)
	{
		packet.val[key].append(mjs[i].val);
	}
	if (mjs.size() == 0)
	{
		packet.val[key].resize(0);
	}
}

void Room::form_player_all_mj_info_json(Player *player, Jpacket &packet, string key)
{
	Json::Value zu_mjs;
	Json::Value out_mjs;
	Json::Value hole_mjs;

	for (unsigned int i=0; i<player->hole_mjs.mjs.size(); i++)
	{
		packet.val[key]["hole_mjs"].append(player->hole_mjs.mjs[i].val);
	}
	if (player->hole_mjs.mjs.size() == 0)
	{
		packet.val[key]["hole_mjs"].resize(0);
	}	
	for (unsigned int i=0; i<player->out_mjs.mjs.size(); i++)
	{
		packet.val[key]["out_mjs"].append(player->out_mjs.mjs[i].val);
	}
	if ( player->out_mjs.mjs.size() == 0 )
	{
		packet.val[key]["out_mjs"].resize(0);
	}
	
	for (unsigned int i=0; i< player->form_mjs.form_mjz.size(); i++)
	{
		MJZ mjz = player->form_mjs.form_mjz[i];
		packet.val[key]["form_mjs"][i]["zu_type"] = mjz.zu_type;
		packet.val[key]["form_mjs"][i]["from_seat"] = mjz.from_seat;
		
		for (unsigned int j=0; j<mjz.zu_mjs.size(); j++)
		{
			packet.val[key]["form_mjs"][i]["zu_mjs"].append(mjz.zu_mjs[j].val);
		}	
	}
	if ( player->form_mjs.form_mjz.size() == 0)
	{
		packet.val[key]["form_mjs"].resize(0);
	}
}


int Room::next_seat(int pos)
{
    for (int i = 0; i < player_num-1; i++)
    {
        pos++; if (pos >= player_num) pos = 0;	
		return pos;
    }
    return -1;
}


Player *Room::next_player(Player *player)
{
	
	int seat = player->seatid;
	int n_seat = next_seat(seat);
	Player *n_player = seats[n_seat].player;
	if (n_player != NULL)
	{
		return n_player;
	}
	else
	{
		GAME_LOG.fatal("function next_player, next_player = NULL.\n");
		return NULL;
	}	
}

Player *Room::next_jiaopai_player(Player *player)
{
	
	int seat = player->seatid;
	int n_seat = next_seat(seat);
	Player *n_player = seats[n_seat].player;
	if (n_player != NULL && n_player->jiaopai_flag == 1)
	{
		return n_player;
	}
	else
	{
		GAME_LOG.fatal("function next_jiaopai_player, next_player = NULL.\n");
		return NULL;
	}	
}


int Room::del_player(Player *player)
{
	if (players.find(player->uid) == players.end())
	{
		GAME_LOG.error("del player in room[%d], player[%d], not int players.\n",roomid,player->uid);
		return -1;
	}
	
	players.erase(player->uid);
	stand_up(player);
	//更新redis里面的房间人数
	if (YXJMJ_CONF._game_flag < 1000000)
	{
		Singleton<RedisClient>::Instance()->
			hset("ROOM_PLAYER_NUM", to_string(rec_id), to_string(players.size()));
	}
    return 0;
}

void Room::del_all_players()
{
    Player *player;
    std::map<int, Player*> tmp = players;
    std::map<int, Player*>::iterator it;
    for (it = tmp.begin(); it != tmp.end(); it++)
    {
        player = it->second;
        YXJMJ_CONF._server->dissolution_room_del_player(player);
    }
	GAME_LOG.info("delete room[%d] all players succ.\n", roomid);
	
	ev_timer_stop(YXJMJ_CONF._loop, &mj_flash_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &dissolution_confirm_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &hu_mj_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &end_flash_timer);
	ev_timer_stop(YXJMJ_CONF._loop, &din_que_timer);
}

int Room::unicast(Player *p, const std::string &packet)
{
    if (p->client)
    {
        return p->client->send(packet);
    }
    return -1;
}

int Room::broadcast(Player *p, const std::string &packet)
{
    Player *player;
    std::map<int, Player*>::iterator it;
    for (it = players.begin(); it != players.end(); it++)
    {
        player = it->second;
        if (player == p || player->client == NULL)
        {
            continue;
        }
        player->client->send(packet);
    }
    return 0;
}

int Room::handler_rebind(Player *player)
{
	GAME_LOG.info("handler_rebind. player[%d]. roomid[%d], state[%d].\n", player->uid, player->roomid, state);
	//刷新玩家状态和刷新房间人数
	if (YXJMJ_CONF._game_flag < 1000000)
	{
		if ( update_db_player_online(player->uid, YXJMJ_CONF._server_id, player->roomid, 1) < 0 )
		{
			GAME_LOG.fatal("handler_rebind, update db error.\n");
		}
		if ( update_gold_room_player_count(YXJMJ_CONF._server_id, YXJMJ_CONF._server->count_server_player_num()))
		{
			GAME_LOG.fatal("handler_rebind, update_gold_room_player_count. error\n");
		}
	}
	else
	{
		if ( update_db_player_online(player->uid, YXJMJ_CONF._server_id, player->roomid, 1) < 0 )
		{
			GAME_LOG.fatal("handler_rebind, update db error.\n");
		}
		if ( update_gold_room_player_count(YXJMJ_CONF._server_id, YXJMJ_CONF._server->count_server_player_num()))
		{
			GAME_LOG.fatal("handler_rebind,  update_gold_room_player_count.error\n");
		}
	}

	player->online = 1;
	
	Jpacket packet;
	packet.val["cmd"] = SERVER_REBIND_UC;	
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = player->roomid;
	packet.val["room_pwd"] = password;
	packet.val["state"] = state;
	packet.val["do_dissolution"] = if_dissolution(); 
	packet.val["board_choose"] = board_choose;	
	packet.val["rest_board"] = rest_board;
	packet.val["player_num"] = player_num;
	packet.val["gang_mo_cnt"] = gang_mo_cnt;
	packet.val["clubid"] = clubid;
	packet.val["priv_uid"] = priv_uid;
	packet.val["rest_mjs"] = comm_mjs.count();

	packet.val["game_flag"] = YXJMJ_CONF._game_flag;
	if (YXJMJ_CONF._game_flag < 1000000) {
		packet.val["base_gold"] = base_gold;
	}
	
	if (state == STATE_PLAYING)
	{
		packet.val["rest_mjs"] = comm_mjs.count();
		if (chongfengji_player == NULL)
		{
			packet.val["chongfengji_seatid"] = -1;			
		}
		else
		{
			packet.val["chongfengji_seatid"] = chongfengji_player->seatid;
		}
	}
	if (state > STATE_READY)
	{
		packet.val["banker_seatid"] = banker_seat;
		packet.val["dice"].append(dice[0]);
		packet.val["dice"].append(dice[1]);
	}

	std::map<int, Player*>::iterator it;	
	int i=0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *p = it->second;
		packet.val["players"][i]["uid"] = p->uid;
		packet.val["players"][i]["seatid"] = p->seatid;
		packet.val["players"][i]["nick_name"] = p->nick_name;
		packet.val["players"][i]["avater_url"] = p->avater_url;
		packet.val["players"][i]["login_ip"] = p->login_ip;
		packet.val["players"][i]["score"] = p->score;
		packet.val["players"][i]["sex"]= p->sex;
		packet.val["players"][i]["gold"] = p->gold;
		packet.val["players"][i]["diamonds"] = p->diamonds;
		packet.val["players"][i]["status"] = p->status;
		packet.val["players"][i]["online"] = p->online;
		packet.val["players"][i]["agree_dissroom"] = p->agree_dissroom;
		packet.val["players"][i]["dq_val"] = p->dq_val;
		packet.val["players"][i]["cur_baoting_flag"] = p->cur_baoting_flag;
		packet.val["players"][i]["robot_opt"] = p->robot_op;
		packet.val["players"][i]["paiwei_score"] = p->paiwei_score;
		
		if ( state > STATE_READY )
		{
			//手上的麻将
			for (unsigned int j=0; j<p->hole_mjs.mjs.size(); j++)
			{
				packet.val["players"][i]["hole_mjs"].append(p->hole_mjs.mjs[j].val);
			}
			if ( p->hole_mjs.mjs.size() == 0)
			{
				packet.val["players"][i]["hole_mjs"].resize(0);
			}
			//打出去的麻将
			for (unsigned int j=0; j<p->out_mjs.mjs.size(); j++)
			{
				packet.val["players"][i]["out_mjs"].append(p->out_mjs.mjs[j].val);
			}
			if ( p->out_mjs.mjs.size() == 0)
			{
				packet.val["players"][i]["out_mjs"].resize(0);
			}
			//组成组的麻将
			for (unsigned int j=0; j< p->form_mjs.form_mjz.size(); j++)
			{
				MJZ mjz = p->form_mjs.form_mjz[j];
				packet.val["players"][i]["form_mjs"][j]["zu_type"] = mjz.zu_type;
				packet.val["players"][i]["form_mjs"][j]["from_seat"] = mjz.from_seat;
				
				for (unsigned int k=0; k<mjz.zu_mjs.size(); k++)
				{
					packet.val["players"][i]["form_mjs"][j]["zu_mjs"].append(mjz.zu_mjs[k].val);
				}	
			}
			if ( p->form_mjs.form_mjz.size() == 0 )
			{
				packet.val["players"][i]["form_mjs"].resize(0);	
			}
		}
		i++;
	}
	GAME_LOG.debug("SERVER_REBIND_UC.\n");
	packet.end();
	unicast(player, packet.tostring());
	GAME_LOG.debug("aaaa.\n");
	//定缺广播
	if (state == STATE_DING_QUE && player->dq_val == 0)
	{
		Jpacket packet;
		packet.val["cmd"] = SERVER_DINGQUE_STARGE_BC;
		packet.val["roomid"] = roomid;
		packet.end();
		unicast(player, packet.tostring());	
	}
	//轮到当前用户操作
	else if ( player->status == INPLAY_AFTER_GETIN_MJ && player->seatid == cur_seat)
	{
		GAME_LOG.debug("bbbb.\n");		
		operate_check_after_getin_mj(player);		
	}
	else if ( player->status == INPLAY_AFTER_PENG_MJ && player->seatid == cur_seat)
	{
		GAME_LOG.debug("cccc.\n");
		operate_check_after_peng_mj(player);
	}
	return 0;
}



int Room::send_all_end_info()
{
	Jpacket packet;
	packet.val["cmd"] = SERVER_GAME_ALL_END_BC;
	packet.val["roomid"] = roomid;
	packet.val["board_choose"] = board_choose;
	int end_board = board_choose - rest_board;
	packet.val["end_board"] = end_board;
	std::string time_str = general_time_str();
	packet.val["time_str"] = time_str.c_str();
	std::map<int, Player*>::iterator it;
	int i=0;
	for (it = players.begin(); it != players.end(); it++)
	{
		Player *player = it->second;
		packet.val["players"][i]["uid"] = player->uid;
		packet.val["players"][i]["avater_url"] = player->avater_url;
		packet.val["players"][i]["nick_name"] = player->nick_name;
		packet.val["players"][i]["zimo_times"] = player->zimo_times;
		packet.val["players"][i]["jiepao_times"] = player->jiepao_times;
		packet.val["players"][i]["dianpao_times"] = player->dianpao_times;
		packet.val["players"][i]["anggang_times"] = player->anggang_times;
		packet.val["players"][i]["minggang_times"] = player->minggang_times;
		for (unsigned int j=0; j<player->vec_score.size(); j++)
		{
			packet.val["players"][i]["score_arr"].append(player->vec_score[j]);
		}
		packet.val["players"][i]["total_score"] = player->score - 1000;
		i++;
	}
	packet.end();
	GAME_LOG.info("SERVER_GAME_ALL_END_BC.\n");
	broadcast(NULL, packet.tostring());
	return 0;
}

int Room::handler_nolmal_chart_req(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	Jpacket packet;
	int type = val["type"].asInt();
	packet.val["cmd"] = SERVER_NOLMAL_CHAT_BC;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["nick_name"] = player->nick_name;
	packet.val["roomid"] = roomid;
	packet.val["type"] = type;
	if ( type == 3 )
	{
		std::string msg = val["message"].asString();
		//std::string out_msg = filter(yxjmj.v_words, msg);
		packet.val["message"] = msg;
	}
	else if (type == 1 || type == 2)
	{
		packet.val["tag"] = val["tag"];
	}
	GAME_LOG.info("SERVER_NOLMAL_CHAT_BC.\n");
	packet.end();
	broadcast(NULL, packet.tostring());
	return 0;
}

int Room::handler_speak_req(Player *player)
{
	Json::Value &val = player->client->packet.tojson();
	Jpacket packet;
	packet.val["cmd"] = SERVER_SPEAK_BC;
	packet.val["uid"] = player->uid;
	packet.val["seatid"] = player->seatid;
	packet.val["roomid"] = roomid;
	packet.val["time_sec"] = val["time_sec"];
	packet.val["sound_url"] = val["sound_url"];
	packet.end();
	GAME_LOG.info("SERVER_SPEAK_BC.\n");
	broadcast(NULL, packet.tostring());
	return 0;
}

int Room::handler_del_player(Player * player)
{
	return YXJMJ_CONF._server->del_player(player);
}

//鍙戠墝鍔ㄧ敾缁撴潫鍚庡洖璋冿紝寮€濮嬫父鎴?
void Room::mj_flash_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	GAME_LOG.debug("mj_flash_timer_out.\n");
	Room *room = (Room*)w->data;
	ev_timer_stop(YXJMJ_CONF._loop, &room->mj_flash_timer);

	room->start_play();
}

//瑙ｆ暎鎴块棿绛夊緟纭瓒呮椂鍥炶皟锛岃В鏁ｆ埧闂?
void Room::dissolution_confirm_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	GAME_LOG.debug("dissolution_confirm_timer_out.\n");
	Room *room = (Room*)w->data;
	ev_timer_stop(YXJMJ_CONF._loop, &room->dissolution_confirm_timer);
	room->do_dissolution_room();
}

//鑳＄墝鍔ㄧ敾鏃堕棿锛屽畾鏃跺紑濮嬫父鎴忕粨绠楃晫闈€?
void Room::hu_mj_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	GAME_LOG.debug("hu_mj_timer_out.\n");
	Room *room = (Room*)w->data;
	ev_timer_stop(YXJMJ_CONF._loop, &room->hu_mj_timer);
	
	room->game_end(0);	
}
//娓告垙缁撴潫鍔ㄧ敾瀹氭椂鍣?
void Room::end_flash_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	GAME_LOG.debug("end_flash_timer_out.\n");
	Room *room = (Room*)w->data;
	ev_timer_stop(YXJMJ_CONF._loop, &room->end_flash_timer);

	room->start_ready();
} 

void Room::din_que_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
	GAME_LOG.debug("din_que_timer_cb.\n");
	Room *room = (Room*)w->data;
	ev_timer_stop(YXJMJ_CONF._loop, &room->din_que_timer);

	room->robot_do_din_que();
} 

void Room::begin_robot_op_bc(Player *player)
{
	Jpacket packet;
	packet.val["cmd"] = SERVER_BEGIN_ROBOT_OP_BC;
	packet.val["uid"] = player->uid;
	packet.val["roomid"] = player->roomid;
	packet.val["seatid"] = player->seatid;
	packet.end();
	GAME_LOG.debug("SERVER_BEGIN_ROBOT_OP_BC.\n");
	broadcast(NULL,packet.tostring());
}


bool Room::if_que_men(Player *player, const Mj &mj)
{
	if (player_num == 4)
	{
		return false;
	}
	
	if ( mj.val / 10 == player->dq_val )
	{
		return true;
	}
	else 
	{ 
		return false;
	}
}

bool Room::check_peng(Player *player, Mj out_mj)
{
	if (if_que_men(player, out_mj)) 
	{
		return false;
	}
	
	int ret = player->hole_mjs.peng_and_gang(out_mj);
	if ( ret == 1 || ret == 2 )
	{
		return true;
	}
	else
	{
		return false;
	}
}
bool Room::check_fang_gang(Player* player, Mj out_mj)
{
	if (if_que_men(player,out_mj)) 
	{
		return false;
	}
	
	if ( player->hole_mjs.peng_and_gang(out_mj) == 2 )
	{
		if ( comm_mjs.count() == 0 ) //最后一张打出去的牌不能杠
		{
			return false;
		}
		else
		{
			return true;
		}		
	}
	else
	{
		return false;
	}
}

bool Room::check_fang_pao_hu(Player *player, Mj out_mj, Player *out_mj_player)
{	
	if (if_que_men(player,out_mj)) 
	{
		return false;
	}	
	std::vector<Mj> temp_mjs;
	temp_mjs = player->hole_mjs.mjs;
	temp_mjs.push_back(out_mj);
	bool ret = check_hupai(temp_mjs, player->dq_val);
	if ( !ret )
	{
		return false;
	}

	if ( player->guo_shou_bu_hu_flag == 1)
	{
		GAME_LOG.debug("guo shou can not hu.\n");
		return false;
	}
	
	//是否地胡
	if (comm_mjs.count() == 108-player_num*13 -1)
	{
		return true;
	}
		
	//玩家在有“豆”的情况下允许点胡。大胡有豆无豆皆可胡牌。
	if ( player->have_gang == 1)
	{
		return true;
	}
	
	if (gang_shang_pao_check_flag)
	{
		return true;
	}

	//计算是否是大胡
	player->hole_mjs.mjs.push_back(out_mj);	
	int cardtype = calculate_card_type(player);
	player->hole_mjs.mjs.pop_back();
	if (cardtype <= 1)
	{
		return false;
	}
	
	return true;
}

bool Room::check_qiang_gang_hu(Player *player, Mj gang_mj, Player *qiang_gang_player)
{
	if (if_que_men(player,gang_mj)) 
	{
		return false;
	}
	std::vector<Mj> temp_mjs;
	temp_mjs = player->hole_mjs.mjs;
	temp_mjs.push_back(gang_mj);
	bool ret = check_hupai(temp_mjs, player->dq_val);
	return ret;
}

//自摸牌后
//有无暗杠
bool Room::check_ang_gang(Player *player, std::vector<int> &vec_gang_val)
{
	//最多14张牌
	unsigned int i_num = player->hole_mjs.mjs.size();
    if( i_num > 14 )
    {
		return false;
    }
	//牌数应为3n+2
    if( i_num%3 != 2)
    {
		return false;
    }
	if (comm_mjs.count() == 0) //只剩最后一张牌不能暗杠了
	{
		return false;
	}
	
	return player->hole_mjs.check_four_same(vec_gang_val, player->dq_val);	
}

bool Room::check_op_ting(Player *player, std::vector<int> &vec_ting_mjval)
{
	//必须14张牌
	unsigned int i_num = player->hole_mjs.mjs.size();
    if( i_num != 14 )
    {
		return false;
    }
	//必须首次摸牌
	//1，如果庄家首次摸牌，天听
	if( player->seatid == banker_seat && player->mo_cnt == 1 )
	{
		if ( check_baoting(player->hole_mjs.mjs, vec_ting_mjval, player->dq_val) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	//2, 非庄家，首次摸牌, 地听
	else if ( player->seatid != banker_seat && player->mo_cnt == 1 ) 
	{
		if ( check_baoting(player->hole_mjs.mjs, vec_ting_mjval, player->dq_val) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	return false;	
}


//检查能否暗杠某张麻将牌
bool Room::check_ang_gang(Player* player, Mj mj)
{
	//最多14张牌
	unsigned int i_num = player->hole_mjs.mjs.size();
    if( i_num > 14 )
    {
		return false;
    }
	//牌数应为3n+2
    if( i_num%3 != 2)
    {
		return false;
    }
	if (comm_mjs.count() == 0) //只剩最后一张牌不能暗杠了
	{
		return false;
	}

	//有缺门的牌
	if (if_que_men(player,mj))
	{
		return false;
	}
	   	
	if ( player->hole_mjs.peng_and_gang(mj) == 3 )
	{
		return true;
	}
	else
	{
		return false;
	}	
}

//看摸得的那张牌能否明杠
bool Room::check_ming_gang(Player* player, Mj mj)
{
	if (if_que_men(player,mj)) 
	{
		return false;
	}
	if (comm_mjs.count() == 0) //只剩最后一张牌不能明杠
	{
		return false;
	}
	return player->form_mjs.check_same_ke_mj(mj);	
}

//检查能否自摸胡牌
bool Room::check_zi_mo_hu(Player* player)
{
	//有缺门的牌
	if ( player_num !=4 && player->hole_mjs.has_que_men(player->dq_val))
	{
		return false;
	}

	bool ret = check_hupai(player->hole_mjs.mjs, player->dq_val);
	if (!ret)
	{
		return false;
	}
	return  true;
}

//计算是否叫牌
int Room::check_jiaopai_flag(Player *player)
{
	if ( player->hole_mjs.mjs.size()%3 == 2 ) //3N+2张牌，必须是胡牌了
	{
		if (check_hupai( player->hole_mjs.mjs, player->dq_val))
		{
			player->jiaopai_flag = 1;
		}
		else
		{
			player->jiaopai_flag = 0;
		}
	}
	else if (player->hole_mjs.mjs.size()%3 == 1 ) //3N+1张牌，必须听牌
	{
		if ( check_ting(player->hole_mjs.mjs, player->dq_val))
		{
			player->jiaopai_flag = 1;
		}
		else
		{
			player->jiaopai_flag = 0;
		}
	}
	else 
	{
		player->jiaopai_flag = 0;
	}
	
	return player->jiaopai_flag;
}


//碰
int Room::do_peng(Player *player, Player * out_player, Mj out_mj)
{
	if ( !check_peng(player,out_mj) )
	{
		GAME_LOG.error("can not peng, player[%d].\n", player->uid);
		return -1;
	}
	out_player->out_mjs.remove_back_mj();	
	remove_n_mj(player->hole_mjs.mjs,out_mj,2);
	player->form_mjs.add_form(PENG, out_mj, out_player->seatid);
	return 0;
}

//放杠
int Room::do_fang_gang(Player *player, Player * out_player, Mj out_mj)
{
	if (!check_fang_gang(player, out_mj))
	{
		GAME_LOG.error("can not fang gang mj[%d]. player[%d].\n",out_mj.val, player->uid);
		return -1;
	}
	
	out_player->out_mjs.remove_back_mj();	
	remove_n_mj( player->hole_mjs.mjs, out_mj, 3);	
	player->form_mjs.add_form(FANG_GANG, out_mj, out_player->seatid);
	player->have_gang = 1;
	
	return 0;
}

//暗杠
int Room::do_ang_gang(Player *player, Mj mj)
{
	if ( !check_ang_gang(player, mj) )
	{
		GAME_LOG.error("can not ang gang mj[%d]. player[%d].\n", mj.val, player->uid);
		return -1;
	}
	
	remove_n_mj( player->hole_mjs.mjs, mj, 4);
	player->form_mjs.add_form(ANG_GANG, mj, player->seatid);
	player->anggang_times++;
	player->have_gang = 1;
	return 0;
}

//明杠
int Room::do_ming_gang(Player *player, Mj mj)
{
	if ( !check_ming_gang(player, mj))
	{
		GAME_LOG.error("can not ming gang mj[%d]. player[%d].\n",mj.val, player->uid);
		return -1;
	}
	remove_n_mj( player->hole_mjs.mjs, mj, 1);
	player->form_mjs.add_form(MING_GANG, mj);
	player->minggang_times++;
	player->have_gang = 1;
	return 0;
}

//出牌
int Room::do_out_mj(Player *player, Mj mj)
{
	remove_n_mj( player->hole_mjs.mjs, mj, 1);
	player->out_mjs.add_mj(mj);
	return 0;
}



int Room::handler_logout(Player *player)
{	
// 	if (YXJMJ_CONF._game_flag < 1000000)
// 	{
// 		GAME_LOG.fatal("handler_logout, but game_flag == 1.\n");
// 		return -1;
// 	}
	if (state != STATE_READY) 
	{
		GAME_LOG.error("handler_logout, but state not STATE_READY.\n");
		return -1;
	}
    Jpacket packet;
    packet.val["cmd"] = SERVER_GOLDROOM_LOGOUT_ROOM;
    packet.val["uid"] = player->uid;
    packet.val["seatid"] = player->seatid;
    packet.val["type"] = player->logout_type;
    GAME_LOG.debug("SERVER_LOGOUT_BC\n");
    packet.end();
    broadcast(NULL, packet.tostring());
    return 0;
}

int Room::handler_cancel_robot_op(Player *player)
{
	
	player->robot_op = 0;
	Jpacket packet;
	packet.val["cmd"] = SERVER_CANCEL_ROBOT_OP_SUCC_BC;
	packet.val["uid"] = player->uid;
	packet.val["roomid"] = player->roomid;
	packet.val["seatid"] = player->seatid;
	packet.end();
	GAME_LOG.debug("SERVER_CANCEL_ROBOT_OP_SUCC_BC.\n");
	broadcast(NULL, packet.tostring());
	return 0;
}



